如何在应用程序shell中实现繁忙指标

时间:2014-08-08 01:04:39

标签: c# wpf mvvm wpftoolkit

我正在尝试在我的应用程序" shell中实现WPF扩展工具包中的忙指示符。"目标是在一个地方实现指标,然后能够从任何地方设置IsBusy属性,以便可以初始化它。这是我的shell:

<Window x:Class="Foundation.Shell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="clr-namespace:Library.Controls.Views;assembly=Library"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    WindowStyle="None"
    AllowsTransparency="False"
    Name="ShellView"
    FontFamily="Yu Gothic Light"
    Background="{StaticResource AiWhiteBrush}">

<!--Region Outer Most Grid-->
<xctk:BusyIndicator IsBusy="{Binding IsBusy}">
    <Grid x:Name="OuterGrid">

<!-- CONTENT HERE -->

    </Grid>
</xctk:BusyIndicator>
<!--End Region-->

然后,我的Shell的ViewModel看起来像这样:

using CashDrawer.Views;
using Library.BaseClasses;
using Library.StaticClasses;
using Microsoft.Practices.Prism.Commands;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using WpfPageTransitions;

namespace Foundation
{
    public class ShellViewModel : ViewModelBase
    {
        #region constructor(s)

        public ShellViewModel()
        {
            StateManager.IsBusyChange += new StateManager.IsBusyHandler(IsBusyEventAction);
        }

        #endregion constructor(s)

        #region properties

        private bool _IsBusy;
        public bool IsBusy
        {
            get
            {
                return _IsBusy;
            }
            set
            {
                if (_IsBusy != value)
                {
                    _IsBusy = value;
                    OnPropertyChanged("IsBusy");
                }
            }
        }

        #endregion properties

        #region actions, functions, and methods

        private void IsBusyEventAction(object sender, EventArgs e)
        {
            if (StateManager.IsBusy)
            {
                this.IsBusy = true;
            }
            else
            {
                this.IsBusy = false;
            }
        }

        #endregion actions, functions, and methods
    }
}

最后,我创建了一个静态StateManager类:

using System;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using WpfPageTransitions;

namespace Library.StaticClasses
{
    public static class StateManager
    {

        private static bool _IsBusy;
        public static bool IsBusy
        {
            get
            {
                return _IsBusy;
            }
            set
            {
                if (_IsBusy != value)
                {
                    _IsBusy = value;
                    IsBusyChange(null, null);
                }
            }
        }

        public delegate void IsBusyHandler(object sender, EventArgs e);

        public static event IsBusyHandler IsBusyChange;
    }
}

这个想法是,当StateManager的IsBusy属性发生更改时,它将触发一个事件,该事件将相应地更改ShellViewModel中的IsBusy属性。逻辑运作正常。但是,忙碌指示器没有按预期工作。以下是来自另一个视图模型的代码片段,用于切换IsBusy属性:

private void SaveCommand_Action()
{
     StateManager.IsBusy = true;

     this.Validate();

     if (!HasValidationErrors)
     {
        if (this.CustomerControlVM.SaveCustomer() != 0)
        {
            VehicleControlVM.VehicleModel.CustomerID = this.CustomerControlVM.CustomerModel.CustomerID;
            this.VehicleControlVM.SaveVehicle();

            ComplaintsView complaintsControl = new ComplaintsView();

            (complaintsControl.DataContext as ComplaintsViewModel).CurrentVehicle = this.VehicleControlVM.VehicleModel;
            (complaintsControl.DataContext as ComplaintsViewModel).CurrentCustomer = this.CustomerControlVM.CustomerModel;
            StateManager.LoadView(complaintsControl, PageTransitionType.SlideLeft);
        }
    }

    StateManager.IsBusy = false;
}

我看到代码有些滞后,但我从未看到繁忙的指示符出现。我可以删除StateManager.IsBusy = false;并显示忙碌指示符(当然会无限期显示。)我尝试在IsBusy状态更改之间创建更长的延迟,但指标仍然没有出现。我已经阅读了多篇帖子和文章,试图了解可能出现的问题,但我没有看到任何有用的信息。我知道IsBusy指标正在UI线程上发生,但我正在改变ViewModel中的IsBusy状态,它不应该在UI线程上。有什么想法或建议吗?

2 个答案:

答案 0 :(得分:2)

关于我的上一次评论。

你可以改变statemanager来接受一个动作,所以你传入方法,状态管理器可以设置调用等

public static class StateManager 
{

public static void Process(Action action) {
    IsBusy = true;
    Application.Current.Dispatcher.Invoke(action, System.Windows.Threading.DispatcherPriority.Background);
    IsBusy = false;
}

private static bool _IsBusy;
public static bool IsBusy {
    get {
        return _IsBusy;
    }
    set {
        if (_IsBusy != value) {
            _IsBusy = value;
            IsBusyChange(null, null);
        }
    }
}

public delegate void IsBusyHandler(object sender, EventArgs e);

public static event IsBusyHandler IsBusyChange;

}

然后你可以这样做:

private void SaveCommand_Action()
{
     StateManager.Process(() =>
     {

     this.Validate();

     if (!HasValidationErrors)
     {
        if (this.CustomerControlVM.SaveCustomer() != 0)
        {
            VehicleControlVM.VehicleModel.CustomerID = this.CustomerControlVM.CustomerModel.CustomerID;
            this.VehicleControlVM.SaveVehicle();

            ComplaintsView complaintsControl = new ComplaintsView();

            (complaintsControl.DataContext as ComplaintsViewModel).CurrentVehicle = this.VehicleControlVM.VehicleModel;
            (complaintsControl.DataContext as ComplaintsViewModel).CurrentCustomer = this.CustomerControlVM.CustomerModel;
            StateManager.LoadView(complaintsControl, PageTransitionType.SlideLeft);
        }
    }

    StateManager.IsBusy = false;
});
}

答案 1 :(得分:1)

感谢sa_ddam213,我有问题。问题是优先事项。这段代码是照顾它的:

    private void SaveCommand_Action()
    {
        StateManager.IsBusy = true;
        Application.Current.Dispatcher.Invoke(() => Save(), System.Windows.Threading.DispatcherPriority.Background);
    }

    private void Save()
    {
        this.Validate();

        if (!HasValidationErrors)
        {
            if (this.CustomerControlVM.SaveCustomer() != 0)
            {
                VehicleControlVM.VehicleModel.CustomerID = this.CustomerControlVM.CustomerModel.CustomerID;
                this.VehicleControlVM.SaveVehicle();

                ComplaintsView complaintsControl = new ComplaintsView();

                (complaintsControl.DataContext as ComplaintsViewModel).CurrentVehicle = this.VehicleControlVM.VehicleModel;
                (complaintsControl.DataContext as ComplaintsViewModel).CurrentCustomer = this.CustomerControlVM.CustomerModel;
                StateManager.LoadView(complaintsControl, PageTransitionType.SlideLeft);
                StateManager.IsBusy = false;
            }
        }
    }

我还有一些工作要做,所以我不需要对每个IsBusy状态更改都这样做,但是根据我所学到的,我可以弄明白。非常感谢sa_ddam213。