关于此:
这可行,但这不是唯一的事件,因此使我的代码变得丑陋
是的 ,除非您理解并接受 WPF的心态,
否则基于WPF的代码肯定会非常恐怖。
基本上,自定义逻辑(AKA业务逻辑或应用程序逻辑)与WPF UI之间的所有交互 都应 以 声明性数据
绑定
的形式体现,而不是传统的命令式方法。
这意味着应该没有这样的东西:
UserWindow.Visibility = Visibility.Hidden;
在代码中的任何位置,仅仅是因为引入诸如此类的操作使您的代码依赖于UI,因此只能在UI线程上执行。
相反,WPF的方法是声明
Visibility性地将UI元素( IN XAML )的属性绑定到可以从外部操作的相关bool属性,如下所示:
<UserWindow Visibility="{Binding ShowUserWindow, Converter={my:BoolToVisibilityConverter}}"> <!-- ... --></UserWindow>然后,您需要创建一个相关类,其中包含UI希望绑定到的属性。这称为
ViewModel 。
请注意,为了正确地支持双向WPF数据绑定,您的ViewModels必须实现
INotifyPropertyChangedinterface。
这样做时,将
PropertyChanged来自该接口的事件 编组到UI线程
也很方便,这样您就不必担心使用来设置ViewModel的属性
Dispatcher。
因此,我们的第一步是让我们所有的ViewModels都从这样的类继承:
(摘自此答案):
public class PropertyChangedbase:INotifyPropertyChanged{ public event PropertyChangedEventHandler PropertyChanged; protected virtual void onPropertyChanged(string propertyName) { //Raise the PropertyChanged event on the UI Thread, with the relevant propertyName parameter: Application.Current.Dispatcher.BeginInvoke((Action) (() => { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); })); }}一旦将 属性更改通知分派到UI线程
,就可以继续创建一个相关的ViewModel,在这种情况下,
UserWindow它符合DataBinding的期望:
public class UserViewModel: PropertyChangedbase{ private bool _showUserWindow; public bool ShowUserWindow { get {return _showUserWindow; } set { _showUserWindow = value; onPropertyChanged("ShowUserWindow"); //This is important!!! } }}最后,您需要将Window的
DataContext 设置为其对应的ViewModel的实例。一种简单的方法是在Window的构造函数中:
public UserWindow() //Window's Constructor{ InitializeComponent(); //this is required. DataContext = new UserViewModel(); //here we set the DataContext}如您在本示例中所看到的,实际上 不需要 在程序代码中操纵UI元素的属性。这很好,不仅因为它解决了 线程亲和性
问题(因为现在您可以
ShowUserWindow从任何线程设置属性),而且还因为它使ViewModel和逻辑完全与UI分离,因此可测试且更具可伸缩性。
同样的概念也适用于WPF中的一切。
有一个细节,我需要提到的是,我利用的技术的结合
MarkupExtension,并
IValueConverter以减少涉及到使用转换器的XAML样板。
您可以在链接以及上面链接的MSDN DataBinding页面中了解有关此内容的更多信息。
让我知道您是否需要更多详细信息。



