C# 您如何处理';选择EditemChanged';MVVM视图模型中的事件?
我有一些依赖于两个属性被设置的逻辑,当两个属性都有值时它就会执行。例如:C# 您如何处理';选择EditemChanged';MVVM视图模型中的事件?,c#,wpf,silverlight,mvvm,C#,Wpf,Silverlight,Mvvm,我有一些依赖于两个属性被设置的逻辑,当两个属性都有值时它就会执行。例如: private void DoCalc() { if (string.IsNullOrEmpty(Property1) || string.IsNullOrEmpty(Property2)) return; Property3 = Property1 + " " + Property2; } 每次Property1或Property2发生更改时都需要执行该代码,但我很难弄清楚如何以一种风格上可以接受的方式
private void DoCalc() {
if (string.IsNullOrEmpty(Property1) || string.IsNullOrEmpty(Property2))
return;
Property3 = Property1 + " " + Property2;
}
每次Property1或Property2发生更改时都需要执行该代码,但我很难弄清楚如何以一种风格上可以接受的方式执行该代码。以下是我看到的选择:
1) 从ViewModel调用方法
我在概念上没有问题,因为逻辑仍然在ViewModel中-我不是一个“无代码隐藏”的纳粹分子。然而,“触发器”逻辑(当任何一个属性改变时)仍然在UI层中,我不喜欢它。代码隐藏将如下所示:
void ComboBox_Property1_SelectedItemChanged(object sender, RoutedEventArgs e) {
viewModel.DoCalc();
}
public string Property1 {
get {return property1;}
set {
if (property1 != value) {
property1 = value;
NotifyPropertyChanged("Property1");
DoCalc();
}
}
}
public ViewModel() {
this.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
}
void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "Property1" || e.PropertyName == "Property2") {
DoCalc();
}
}
2) 从属性设置器调用方法
这种方法似乎是最“纯粹”的,但也似乎很丑陋,似乎逻辑是隐藏的。它看起来是这样的:
void ComboBox_Property1_SelectedItemChanged(object sender, RoutedEventArgs e) {
viewModel.DoCalc();
}
public string Property1 {
get {return property1;}
set {
if (property1 != value) {
property1 = value;
NotifyPropertyChanged("Property1");
DoCalc();
}
}
}
public ViewModel() {
this.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
}
void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "Property1" || e.PropertyName == "Property2") {
DoCalc();
}
}
3) 钩住PropertyChanged事件
我现在认为这可能是正确的方法,但在实现的viewmodel中挂接property changed事件感觉很奇怪。它看起来像这样:
void ComboBox_Property1_SelectedItemChanged(object sender, RoutedEventArgs e) {
viewModel.DoCalc();
}
public string Property1 {
get {return property1;}
set {
if (property1 != value) {
property1 = value;
NotifyPropertyChanged("Property1");
DoCalc();
}
}
}
public ViewModel() {
this.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
}
void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "Property1" || e.PropertyName == "Property2") {
DoCalc();
}
}
所以,我的问题是,如果您浏览一些具有该需求的源代码,您希望看到实现哪种方法(为什么?)。谢谢你的意见。我不认为在setter中这样做很难看。。。实际上,这可能是您提到的3种方法中最好的,因为当您阅读代码时,您会立即看到更改
Property1
或Property2
的值将重新计算Property3
;这在其他两种方法中根本不明显
然而,我不会使用这两个选项。我认为更好的方法是使Property3
只读,并根据Property1
和Property2
在getter中计算其值:
public string Property3
{
get { return Property3 = Property1 + " " + Property2; }
}
这样,在
Property1
和Property2
的设置程序中,您只需调用NotifyPropertyChanged
来设置Property3
。Yes@Thomas是正确的。在WPF环境中,方法2是一种完美的方法。前提是您已将ListBox.SelectedValue双向绑定添加到属性1
您的(1)无效,因为它将业务逻辑公开给视图。(3) 是一个不必要的事件处理,它无论如何都是由Property1 setter代码触发的。所以最好直接从Setter调用它。所以MVVM的方式是(2)(2)是我通常的方式
也就是说,这让我想知道是否有其他方法可以使用Rx框架来完成这类工作:
所以这就是我想到的(警告——不要这样做!)
公共类视图模型:INotifyPropertyChanged
{
公共视图模型()
{
var o1=
可观察的。从事件(本“财产变更”);
订阅(e=>Debug.WriteLine(e.EventArgs.PropertyName));
var o2=o1.SkipWhile(e=>e.EventArgs.PropertyName!=“Property1”);
var o3=o1.SkipWhile(e=>e.EventArgs.PropertyName!=“Property2”);
var o4=o1.SkipWhile(e=>e.EventArgs.PropertyName!=“结果”);
var o5=可观察的。组合测试(o2,o3,(e1,e2)=>DoStuff())。TakeUntil(o4);
订阅(o=>Debug.WriteLine(“获得了Prop1和Prop2”);
}
公共字符串DoStuff()
{
返回结果=string.Concat(Property1,Property2);
}
私有字符串_属性1;
公共字符串属性1
{
获取{return\u property1;}
设置
{
_财产1=价值;
OnNotifyPropertyChanged(“Property1”);
}
}
私有字符串_property2;
公共字符串属性2
{
获取{return\u property2;}
设置
{
_财产2=价值;
OnNotifyPropertyChanged(“Property2”);
}
}
私有字符串_结果;
公共字符串结果
{
获取{return\u result;}
设置
{
_结果=值;
OnNotifyPropertyChanged(“结果”);
}
}
公共事件属性更改事件处理程序属性更改;
私有void OnNotifyPropertyChanged(字符串名称)
{
var handler=PropertyChanged;
if(处理程序!=null)
{
处理程序(此,新PropertyChangedEventArgs(名称));
}
}
}
除非第三个属性像您的示例中那样微不足道,否则setterProperty1
和Property2
还应该设置一些IsProperty3Invalid
标志,Property3
的getter将检查是否需要再次调用DoCalc
。这是一个有趣的想法(我显然没有考虑)。我必须考虑一下,因为在“真实”代码中,属性3有时是由prop1和prop2设置的,但如果不是由这些条件设置的,则用户必须手动填写。可以使用这种方法完成……我将对其进行编码并查看其外观。很好。标记正确,只是为了给您一些道具,但不确定我是否100%同意。需要沉浸其中:)@gabe,是的,很好。如果属性需要大量计算,则不应该每次我同意在setter中执行时都重新计算它,因为recalc确实是通过设置prop1/2触发的,因此它非常合理且可读。用第三个属性扩展您的想法:我宁愿使用带有备份字段和私有getter的公共属性。对于视图绑定到属性的情况,这将启用“缓存”并从属性的“内部”触发PropertyChanged事件。我不会那样做;-)