我正在尝试在我的应用程序" 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线程上。有什么想法或建议吗?
答案 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。