[英]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.