我一直在試圖弄清楚如何在幾天內完成此操作。維護響應式WPF UI
這是一個相當普遍的問題,所以我會說明情況,如一般地,所以也許別人能有點用的出來。
我有我的WPF列表視圖(使用MVVM)對話框,它一定有,比如說物品,這顯示在單獨列五個屬性的可觀察集合。
我調用一個函數,這對所有的項目進行迭代,並改變它們的屬性之一。此功能需要一段時間才能完成所有項目,因此我希望它在每個項目更新時都進行更新。
有什麼要做到這一點,因此UI仍然可以做出響應的選項,這是最簡單的實現?
我一直在試圖弄清楚如何在幾天內完成此操作。維護響應式WPF UI
這是一個相當普遍的問題,所以我會說明情況,如一般地,所以也許別人能有點用的出來。
我有我的WPF列表視圖(使用MVVM)對話框,它一定有,比如說物品,這顯示在單獨列五個屬性的可觀察集合。
我調用一個函數,這對所有的項目進行迭代,並改變它們的屬性之一。此功能需要一段時間才能完成所有項目,因此我希望它在每個項目更新時都進行更新。
有什麼要做到這一點,因此UI仍然可以做出響應的選項,這是最簡單的實現?
如果您正在使用C# 4.0
,使用
Task.Factory.StartNew(new Action(() =>
{
.....
//CALL YOUR UPDATE METHOD
})).ContinueWith({ //something to execute after, if need}..)
,並設置其它線程ModelView
對象時,使用
Application.Current.Dispatcher.Invoke(new Action(() =>
{
//set ModelView object properties here
}));
不過要小心,如果你想操縱'Task'的延續UI元素,你必須用'TaskScheduler.FromCurrentSynchronizationContext()'選項創建所述延續。 :) –
謝謝,這很完美 - 簡潔而簡單。 –
我會用一個ObservableCollection擴展,使您可以更新另一個集合線。這是我在我的應用程序中使用與收藏品交易時:
public class ObservableCollectionExtender<T> : ObservableCollection<T>
{
/// <summary>
/// Source: New Things I Learned
/// Title: Have worker thread update ObservableCollection that is bound to a ListCollectionView
/// http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx
/// Note: Improved for clarity and the following of proper coding standards.
/// </summary>
/// <param name="e"></param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// Use BlockReentrancy
using (BlockReentrancy())
{
var eventHandler = CollectionChanged;
// Only proceed if handler exists.
if (eventHandler != null)
{
Delegate[] delegates = eventHandler.GetInvocationList();
// Walk thru invocation list
foreach (NotifyCollectionChangedEventHandler handler in delegates)
{
var currentDispatcher = handler.Target as DispatcherObject;
// If the subscriber is a DispatcherObject and different thread
if ((currentDispatcher != null) &&
(currentDispatcher.CheckAccess() == false))
{
// Invoke handler in the target dispatcher's thread
currentDispatcher.Dispatcher.Invoke(
DispatcherPriority.DataBind, handler, this, e);
}
else
{
handler(this, e);
}
}
}
}
}
/// <summary>
/// Overridden NotifyCollectionChangedEventHandler event.
/// </summary>
public override event NotifyCollectionChangedEventHandler CollectionChanged;
}
嘿,謝謝你的答案 - 一個很好的選擇。我已經跟Tigran完全脫離了他先回答的事實。 –
沒問題。我提出這個問題的唯一原因是因爲我不需要故意關心更新UI。這隻需要對UI中立即反映的集合進行更新,而不會影響UI線程。當你積極地更新網格(每秒一次)時,你會想嘗試這樣的事情。祝你好運。 – Xcalibur37
一種簡單的方法,也是誰是Netframework 3.5工作的人,可能會在後臺線程工作,使用同步大賽同步。試試這個:
var sync = SynchronizationContext.Current;
BackgroundWorker w = new BackgroundWorker();
w.DoWork+=(_, __)=>
{
foreach (var item in collection)
{
//calculate other things
sync.Post(p => { ...Actualize UI code... }, null);
}
}, null);
};
w.RunWorkerAsync();
只是不要在你的UI線程中這樣做。 – Jon
你應該在後臺線程上做這個工作,讓它回調主線程(使用Dispatcher)。如果列表視圖中的對象的屬性已連接INotifyPropertyChanged,則它們將觸發UI的刷新。你只需要確保你在主UI線程上進行更新。 – tomasmcguinness
喬恩和托馬斯說了些什麼。我想補充一點,向用戶提供某種反饋,比如列表中的加載圖標也很重要。假設您正在使用MVVM,則只要您的操作開始並停止並將忙指示符綁定到該屬性,就可以在VM中設置一個屬性。 – MrEdge