我的C#应用​​程序具有一个数据提供程序组件,该组件在其自己的线程中异步更新。 ViewModel类均从实现INotifyPropertyChanged的基类继承。为了让异步数据提供者使用PropertyChanged事件更新View中的属性,我发现我的ViewModel与视图紧密结合,因为只需要从GUI线程中引发事件!#region INotifyPropertyChanged/// <summary>/// Raised when a property on this object has a new value./// </summary>public event PropertyChangedEventHandler PropertyChanged;/// <summary>/// Raises this object's PropertyChanged event./// </summary>/// <param name="propertyName">The property that has a new value.</param>protected void OnPropertyChanged(String propertyName){ PropertyChangedEventHandler RaisePropertyChangedEvent = PropertyChanged; if (RaisePropertyChangedEvent!= null) { var propertyChangedEventArgs = new PropertyChangedEventArgs(propertyName); // This event has to be raised on the GUI thread! // How should I avoid the unpleasantly tight coupling with the View??? Application.Current.Dispatcher.BeginInvoke( (Action)(() => RaisePropertyChangedEvent(this, propertyChangedEventArgs))); }}#endregion是否有任何策略可以消除ViewModel与View实现之间的这种耦合?编辑1此answer是相关的,并突出了更新集合的问题。但是,建议的解决方案也使用当前的调度程序,我不想成为我的ViewModel的关注对象。编辑2深入研究上面的问题,我发现了一个链接answer确实回答了我的问题:在View中创建一个Action DependencyProperty,该View模型可用于将View(无论可能是什么)获取到必要时处理调度。编辑3出现的问题是“没有意义”。但是,当我的ViewModel将Observable Collection作为要绑定的视图的属性公开时(请参见EDIT 1),它仍然需要访问Add()的调度程序。例如:App.xaml.csusing System;using System.Collections.ObjectModel;using System.ComponentModel;using System.Threading;using System.Threading.Tasks;using System.Windows;namespace MultiThreadingGUI{ /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { public App() { Startup += new StartupEventHandler(App_Startup); } void App_Startup(object sender, StartupEventArgs e) { TestViewModel vm = new TestViewModel(); MainWindow window = new MainWindow(); window.DataContext = vm; vm.Start(); window.Show(); } } public class TestViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public ObservableCollection<String> ListFromElsewhere { get; private set; } public String TextFromElsewhere { get; private set; } private Task _testTask; internal void Start() { ListFromElsewhere = new ObservableCollection<string>(); _testTask = new Task(new Action(()=> { int count = 0; while (true) { TextFromElsewhere = Convert.ToString(count++); PropertyChangedEventHandler RaisePropertyChanged = PropertyChanged; if (null != RaisePropertyChanged) { RaisePropertyChanged(this, new PropertyChangedEventArgs("TextFromElsewhere")); } // This throws //ListFromElsewhere.Add(TextFromElsewhere); // This is needed Application.Current.Dispatcher.BeginInvoke( (Action)(() => ListFromElsewhere.Add(TextFromElsewhere))); Thread.Sleep(1000); } })); _testTask.Start(); } }}MainWindow.xaml<Window x:Class="MultiThreadingGUI.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" SizeToContent="WidthAndHeight"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="TextFromElsewhere:" /> <Label Grid.Row="0" Grid.Column="1" Content="{Binding Path=TextFromElsewhere}" /> <Label Grid.Row="1" Grid.Column="0" Content="ListFromElsewhere:" /> <ListView x:Name="itemListView" Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Path=ListFromElsewhere}"> <ListView.ItemTemplate> <DataTemplate> <Label Content="{Binding}" /> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid></Window>因此,如何避免对BeginInvoke的调用呢?我是否需要重新发明轮子并为列表创建一个ViewModel容器?还是可以将Add()委托给View? (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 (来自您的编辑)将更新发送到UI以便通过Actions进行调度不仅很麻烦,而且完全没有必要。与在VM中使用Dispatcher或SynchronizationContext相比,您绝对没有任何好处。不要那样做请。它一文不值。当绑定绑定到实现INotifyPropertyChanged *的对象时,绑定将自动处理UI线程上的调用更新。废话,你说?花一点时间,创建一个小的原型进行测试。前进。我会等。 ... 告诉过你。因此,您的问题实际上是有争议的-您完全不必担心这一点。*对框架的此更改是在3.5,iirc中引入的,因此如果您针对3进行构建,则该更改不适用。 (adsbygoogle = window.adsbygoogle || []).push({});
07-24 09:48
查看更多