[英]How to properly implement Busy Indicator from WPF Extended Toolkit
好吧,我一直在努力解決這個問題很長一段時間,並且已經閱讀了一篇文章,試圖了解這個問題。 我正在嘗試實施忙碌指標,但我只是部分成功。 我有一個Shell視圖,我用BusyIndicator包裝,如下所示:
<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:l="clr-namespace:Library.StaticClasses"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Name="ShellView"
Style="{StaticResource BusyWindowStyle}"
SourceInitialized="Window_SourceInitialized"
DataContext="{StaticResource ShellVM}">
<xctk:BusyIndicator x:Name="ShellBusyIndicator" IsBusy="{Binding IsBusy}" DisplayAfter="0">
<Grid>
<!--Content Here -->
</Grid>
</xctk:BusyIndicator>
遵循MVVM模式,我有一個看起來像這樣的ShellViewModel:
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");
}
}
}
private string _IsBusyMessage;
public string IsBusyMessage
{
get
{
return _IsBusyMessage;
}
set
{
if (_IsBusyMessage != value)
{
_IsBusyMessage = value;
OnPropertyChanged("IsBusyMessage");
}
}
}
#endregion properties
#region actions, functions, and methods
private void IsBusyEventAction(object sender, EventArgs e)
{
if (StateManager.IsBusy)
{
this.IsBusy = true;
this.IsBusyMessage = StateManager.IsBusyMessage;
}
else
{
this.IsBusy = false;
}
}
#endregion actions, functions, and methods
}
接下來,我使用一個名為StateManager的靜態類,我可以從任何可以觸發忙指示符的地方調用它:
public static class StateManager
{
public static String IsBusyMessage { get; set; }
public static void IsBusyProcess(Action action)
{
IsBusyProcess(action, "Processing...");
}
public static void IsBusyProcess(Action action, String isBusyMessage)
{
IsBusyMessage = isBusyMessage;
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;
}
最后,我在代碼中觸發忙指示符,如下所示:
StateManager.IsBusyProcess(() =>
{
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。 更改StateManager.IsBusy屬性后,將觸發在ShellViewModel中訂閱的事件。 發生這種情況時,ShellViewModel中的IsBusy屬性設置為true,從而導致顯示IsBusy指示符。 邏輯正常工作正在設置ShellViewModel中的IsBusy並且忙指示器按預期顯示。 什么是不正常的是繁忙的指標不動畫。 它只是停滯不前。 我覺得這是一個線程問題但是我對UI線程的理解是傾斜的,或者我沒有看到一些對你來說很明顯的東西。 我意識到IsBusy邏輯不能與UI在同一個線程上,但我認為,由於我的邏輯發生在視圖模型中,它應該不是問題。 我錯了嗎? 任何想法或想法? 另一件可能有用的事情是:我甚至無法顯示指標並創建此帖子已解決: 如何在應用程序shell中實現繁忙指標
好吧,我終於實現了忙碌指標。 這是一項艱巨的任務,但我已經學到了一些東西。 至少我有一些東西可以展示它。 雖然我沒有弄清楚為什么我的代碼沒有按照我發布的那樣工作,但我確實發現我試圖在動作中執行與UI相關的代碼,這肯定會成為一個問題。 我不是百分百肯定,因為我做了一些重寫,而且我沒有足夠的時間來恢復我的代碼來玩它。 但是,問題得到了解答,以下是我實施繁忙指標的方法:
首先,除了可以刪除IsBusy的屬性集和綁定之外,我的視圖中沒有任何更改。 我最終將視頻模型中的事件訂閱移動到視圖后面的代碼中。 我的觀點背后的代碼如下所示:
public partial class Shell : Window
{
#region Constructor(s)
public Shell()
{
InitializeComponent();
StateManager.IsBusyChange += new StateManager.IsBusyHandler(InitiateIsBusy);
}
#endregion Constructor(s)
#region Event Actions
public void InitiateIsBusy(object sender, BusyActionEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (o, ea) =>
{
e.IsBusyAction.Invoke();
//Dispatcher.Invoke((Action)(() => e.IsBusyAction()));
};
worker.RunWorkerCompleted += (o, ea) =>
{
this.ShellBusyIndicator.IsBusy = false;
};
this.ShellBusyIndicator.BusyContent = e.BusyMessage;
this.ShellBusyIndicator.IsBusy = true;
worker.RunWorkerAsync();
}
#endregion Event Actions
}
首先,請注意我創建了擴展EventArgs的BusyActionEventArgs類。 它被放入我的Library項目中,該項目依賴於我的解決方案中的每個項目:
public class BusyActionEventArgs : EventArgs
{
public Action IsBusyAction { get; set; }
public string BusyMessage { get; set; }
}
最后,我的StateManager現在看起來像這樣:
public static class StateManager
{
public static void IsBusyProcess(Action action)
{
IsBusyProcess(action, "Processing...");
}
public static void IsBusyProcess(Action action, String isBusyMessage)
{
BusyActionEventArgs args = new BusyActionEventArgs()
{
IsBusyAction = action,
BusyMessage = isBusyMessage
};
IsBusyChange(null, args);
}
public delegate void IsBusyHandler(object sender, BusyActionEventArgs e);
public static event IsBusyHandler IsBusyChange;
}
請注意,我為IsBusyProcess方法創建了一個重載,因此如果我願意,我可以發送自定義忙消息。
現在,如果我從我的問題的代碼片段中修改我實際使用Busy Indicator的代碼,它看起來像這樣:
StateManager.IsBusyProcess(() =>
{
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);
請注意我從操作范圍中刪除的代碼。 此代碼是UI代碼,如果它在范圍內,將導致錯誤。
我希望這可以幫助那些可能想要實現類似或遇到麻煩的人。 感謝stackoverflow剛剛存在於此。 有時說出(或打字)會有所不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.