[英]WPF: Change databinding while using MVVM
以下是我真正想做的事情的简化示例,但是我的疑问是相同的。
假设我有两个对象,男人和女人,它们都有相同的属性(年龄,身高和体重),但是它们是两个不同的对象。 我无法改变。
现在,假设我有一个WPF面板,它是使用MVVM原理制作的,可在文本框中显示某个人的年龄。 为此,我使用Text =“ {Binding Path = OnePerson.Age}”,其中OnePerson是在视图模型中定义的Man类型的对象。
这工作正常,但我想要一个类似的页面来显示女人的信息。 理想情况下,我只想使用与以前相同的视图和视图模型。 但这很棘手,因为数据绑定指向人对象OnePerson。 我可以以编程方式更改数据绑定(如WPF绑定编程中所述),但是只能从后面的视图代码中进行更改。 不允许这样做,因为我们使用的是MVVM模型。
我想让OnePerson引用男人或女人对象,但是我不知道这样做的好方法。 它们是不同的类型,因此我不能仅使用if语句分配男人或女人。 我可以将OnePerson声明为对象而不是类型,但是那样我就再也无法轻松访问Age,Height和Weight属性。 或者,我可以创建一个完全不同的ViewModel,其中一个将OnePerson声明为男人,另一个将其声明为Woman,然后对两者使用相同的View。 我认为应该可以,但是对于单个视图有两个视图模型似乎有些奇怪。 当我开始添加功能(例如添加新的Man / Woman或编辑现有的Man / Woman)时,添加我自己的Person类并在Man和Woman之间进行转换可能会使整个视图模型变得相当复杂。复制并粘贴Man视图和视图模型,然后仅将OnePerson对象更改为Woman。
我的问题是,在这种情况下,有没有一种干净简单的方法来使用单个View和Viewmodel显示男人或女人的信息。 还是我不应该为这些情况而烦恼并使页面分开?
希望这足够清楚。
我认为与View或绑定相比,这在ViewModel
上更是一个问题。 View
仅是ViewModel
的可视化表示,听起来您的问题需要在ViewModel
,而不是在View
。
WPF的绑定系统仅在绑定无效的情况下才会发出警告,并且它不在乎DataContext
数据类型。 您的问题( {Binding OnePerson.Age}
)中显示的{Binding OnePerson.Age}
将正确评估,而不管OnePerson
是Man
还是Woman
对象,并且将显示该对象上任何Age
属性的值。
因此,最好的解决方案是将OnePerson
属性设置为可以是Man
或Woman
。 包含所有共享属性的接口将是理想的,因为这样它的属性可以被代码访问而无需强制转换,并且您可以保留所有已经拥有的绑定。
IPerson OnePerson { get; set; }
如果无法使用共享接口,而只能使用object
,那么您需要记住在代码中引用OnePerson
对象到Man
或Woman
类之前, OnePerson
转换为Man
或Woman
类。
object OnePerson { get; set; }
...
if (((Man)OnePerson).Age < 0) ...
第二种方法是创建两个单独的属性,一个用于Man
,一个用于Woman
。 然后,您可以从ViewModel
轻松访问正在使用的任何项目的属性,并且可以将单个View用于ViewModel。
Man SomeMan { get; set; }
Woman SomeWoman { get; set; }
您可能需要一些标志来标识哪个是已填充的对象,并使用该标志来更新对象的属性以及确定视图的DataContext
这是一个使用标志来确定DataContext
的示例
<Style x:Key="MyContentControlStyle">
<Setter Property="Content" Value="{Binding SomeMan}" />
<Style.Triggers>
<DataTrigger Property="{Binding SelectedPersonType}" Value="Woman">
<Setter Property="Content" Value="{Binding SomeWoman}" />
</DataTrigger>
</Style.Triggers>
</Style>
当然,如果您确实使用单独的ViewModel
或希望为每种对象类型使用单独的模板,则可以使用诸如隐式DataTemplates
类的方法轻松地确定如何绘制每个对象。
<DataTemplate DataType="{x:Type myModels:Man}">
<myViews:ManUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type myModels:Woman}">
<myViews:WomanUserControl />
</DataTemplate>
<ContentPresenter Content="{Binding SelectedPerson}" />
总的来说,我建议您要么使OnePerson
成为两个对象都共享的数据类型,要么为这两个对象创建一个单独的ViewModel
。 听起来两个类都很相似,所以您甚至可以摆脱某种通用的ViewModel
,例如PersonViewModel<T>
,在其中将Man
或Woman
传递为T
您是否考虑过基于接口对象创建对象。 该接口基本上会创建一个合同,规定从其派生的任何东西都必须具有至少已声明的内容...派生的控件可以具有更多,但至少要具有所需的东西。 例如。
public interface IPersonProperties
{
string PersonName { get; set; }
int Age { get; set; }
// if you want a function that is common between them too
bool SomeCommonFunction(string whateverParms);
etc...
}
public class Man : IPersonProperties
{
// these required as to support the IPersonProperties
public string PersonName { get; set; }
public int Age { get; set; }
public bool SomeCommonFunction(string whateverParms)
{ doSomething;
return true;
}
// you can still have other stuff specific to man class definition
public string OtherManBasedProperty { get; set;}
public void SomeManFunction()
{ // do something specific for man here }
}
public class Woman : IPersonProperties
{
// these required as to support the IPersonProperties
public string PersonName { get; set; }
public int Age { get; set; }
public bool SomeCommonFunction(string whateverParms)
{ doSomething;
return false;
}
// you can still have other stuff specific to WOMAN class definition
public string OtherWOMANBasedProperty { get; set;}
public void SomeWomanFunction()
{ // do something specific for man here }
}
然后,在您的MVVM中,您可以公开的“对象”是IPersonProperty的对象,例如
public class YourMVVM
{
public IPersonProperties BindToMe{ get; set }
public YourMVVM()
{
BindToMe = new Man();
// OR... BindToMe = new Woman();
}
}
然后,在您创建对象的MVVM对象中的任何位置执行操作。 您的绑定是相同的,但可以是任何性别。 如果通过界面在它们之间存在某些共同点,则可以通过以下方式简单地进行引用
if( BindToMe.SomeCommonFunction( "testing"))
blah blah.
但是,如果您需要通过某种方法根据特定性别来做某事,则可以...
if( BindToMe is Man )
((Man)BindToMe).SomeManFunction();
else
((Woman)BindToMe).SomeWOMANFunction();
希望这会为您提供一些实现选择的门。
如果您只想使用一个xaml控件来满足您的年龄,则可以
ageusercontrol
<TextBlock Text="{Binding Path=Age}" />
personview
<local:AgeUserControl DataContext="{Binding Path=MyObjectTypePersonProperty} />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.