[英]INotifyPropertyChanged/Binding?
我試圖弄清楚如何從另一個線程更新我的主UI(例如文本塊)。 到目前為止,我能夠做到的唯一方法是使用Progress對象。 我遇到無法使用Progress對象的情況,最近有人指出我使用MVVM /綁定方法。 我看了一些視頻並做了一些例子,但似乎無法正常工作。
<TextBlock Name="txtblock1" Text="{Binding count}"></TextBlock>
這是我的錯誤
引發的異常:System.Runtime.WindowsRuntime.dll中的'System.Runtime.InteropServices.COMException'引發的異常:mscorlib.ni.dll中的'System.Runtime.InteropServices.COMException'引發的異常:'System.Runtime.InteropServices.COMException'在mscorlib.ni.dll中
查看(后面的代碼)
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
ViewModelexample obj = new ViewModelexample();
txtblock1.DataContext = obj;
obj.Methodasync();
}
}
視圖模型
public class ViewModelexample : INotifyPropertyChanged
{
public string count { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void onPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler !=null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public async void Methodasync()
{
await Method();
}
public Task Method()
{
return Task.Factory.StartNew(() =>
{
for (int i = 0; i < 100; i++)
{
Task.Delay(1000).Wait();
Debug.WriteLine(i.ToString());
count = i.ToString();
onPropertyChanged(i.ToString());
}
});
}
}
關於我可能做錯了什么的任何想法?
謝謝
您的count
屬性需要能夠通知它已更改
public class ViewModelexample : INotifyPropertyChanged
{
private string _count;
public string count {
get { return _count; }
set {
if(value != _count) {
_count = value;
OnPropertyChanged(nameof(count));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
// the new Null-conditional Operators are thread-safe:
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private int _testCount = 0;
public void Method() {
testCount++;
Debug.WriteLine(testCount.ToString());
count = testCount.ToString();
}
}
上面的工作是因為新的Null條件運算符是線程安全的 :
空條件成員訪問的另一種用法是以更少的代碼以線程安全的方式調用委托。 ...這種新方法是線程安全的,因為編譯器生成的代碼僅一次評估PropertyChanged,並將結果保存在一個臨時變量中。
要測試它,您可以編輯ViewModel方法,並讓視圖在諸如頁面加載或單擊按鈕之類的事件上調用它。
public sealed partial class MainPage : Page
{
ViewModelexample obj = null;
public MainPage()
{
this.InitializeComponent();
obj = new ViewModelexample();
this.DataContext = obj;
}
public void OnSomeEventHandler() {
obj.Method();
}
}
我當時以為綁定將負責交叉線程調用。
不,這僅適用於某些 MVVM框架(例如WPF)。 因此,我更喜歡將所有ViewModel都視為屬於UI。
使用代碼示例,您應該可以使用Progress<T>
:
public async void Methodasync()
{
var progress = new Progress<int>(value =>
{
count = value;
onPropertyChanged("count");
});
await Method(progress);
}
public Task Method(IProgress<int> progress)
{
return Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
Task.Delay(1000).Wait();
Debug.WriteLine(i.ToString());
progress.Report(i);
}
});
}
另請注意,我從StartNew
更改為Run
。 通常, 出於我在博客中描述的原因 ,請勿使用StartNew
。
如果“出於認真考慮”由於某種奇怪的原因而不能使用Progress<T>
,則可以直接使用Reactive Extensions或SynchronizationContext
。
使用SynchronizationContext
示例:
public Task Method()
{
var context = SynchronizationContext.Current;
return Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
Task.Delay(1000).Wait();
Debug.WriteLine(i.ToString());
var localI = i;
context.Post(() =>
{
count = localI;
onPropertyChanged("count");
});
}
});
}
localI
事情是避免關閉循環變量 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.