C# WPF:在使用MVVM时更改数据绑定
下面是一个简单的例子,说明了我真正想做的事情,但我的问题是相同的 假设我有两个对象,男人和女人,它们都具有相同的属性(年龄、身高和体重),但它们是两个不同的对象。我不能改变这一点 现在假设我有一个WPF面板,使用MVVM原理制作,在文本框中显示某个男人的年龄。我使用Text=“{Binding Path=OnePerson.Age}”,其中OnePerson是viewmodel中定义的Man类型的对象 这很好,但我想要一个类似的页面来显示女性的信息。理想情况下,我希望使用与以前相同的视图和视图模型。但这很棘手,因为数据绑定指向Man对象OnePerson。我可以通过编程方式更改数据绑定(如中所述),但只能从视图的代码隐藏中进行更改。我不允许这样做,因为我们使用的是MVVM模型 我想让一个人引用一个男人或女人对象,但我不知道这样做的好方法。它们是不同的类型,所以我不能只使用if语句指定一个男人或女人。我可以将一个人声明为一个对象而不是一个类型,但是我再也不能如此轻松地访问年龄、身高和体重属性了。或者我可以制作一个完全不同的视图模型,其中一个声明一个人为男性,另一个声明一个人为女性,并对他们两人使用相同的视图。我认为这应该行得通,但在一个视图中使用两个ViewModel似乎有点奇怪。添加我自己的Person类并将其与男性或女性进行转换可能会使整个viewmodel变得更加复杂,因为我开始添加功能,如添加新的男性/女性或编辑现有的男性/女性,到了这样的程度,我还可以复制粘贴“男人”视图和“视图”模型,只将“一个人”对象更改为“女人” 我的问题是,在这种情况下,是否有一种简洁的方法可以使用单个视图和Viewmodel来显示男性或女性的信息。或者我不应该费心为这些案例制作单独的页面C# WPF:在使用MVVM时更改数据绑定,c#,wpf,xaml,data-binding,mvvm,C#,Wpf,Xaml,Data Binding,Mvvm,下面是一个简单的例子,说明了我真正想做的事情,但我的问题是相同的 假设我有两个对象,男人和女人,它们都具有相同的属性(年龄、身高和体重),但它们是两个不同的对象。我不能改变这一点 现在假设我有一个WPF面板,使用MVVM原理制作,在文本框中显示某个男人的年龄。我使用Text=“{Binding Path=OnePerson.Age}”,其中OnePerson是viewmodel中定义的Man类型的对象 这很好,但我想要一个类似的页面来显示女性的信息。理想情况下,我希望使用与以前相同的视图和视图模
希望这足够清楚。您是否考虑过基于接口对象制作对象。接口基本上创建了一个契约,声明从它派生的任何东西必须至少具有它声明的内容。。。派生控件可以有更多,但至少是您想要的。比如说
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中,可以公开的“对象”是IPersonProperties的对象,例如
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();
希望这能为您打开一些实现选择的大门。您是否考虑过基于接口对象创建对象。接口基本上创建了一个契约,声明从它派生的任何东西必须至少具有它声明的内容。。。派生控件可以有更多,但至少是您想要的。比如说
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中,可以公开的“对象”是IPersonProperties的对象,例如
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}" />
个人观点
<local:AgeUserControl DataContext="{Binding Path=MyObjectTypePersonProperty} />
如果您只想针对您的年龄使用一个xaml控件,您可以这样做
ageusercontrol
<TextBlock Text="{Binding Path=Age}" />
个人观点
<local:AgeUserControl DataContext="{Binding Path=MyObjectTypePersonProperty} />
我认为与视图或绑定相比,ViewModel
的问题更多。视图
仅仅是视图模型
的一个可视表示,听起来您的问题需要在视图模型
中解决,而不是在视图
中解决
WPF的绑定系统仅在绑定无效时发出警告,并且它不关心DataContext
的数据类型。您问题中显示的绑定({binding OnePerson.Age}
)将正确计算,无论OnePerson
是Man
还是Woman
对象,并将显示该对象上任何Age
属性的值
因此,最好的解决方案是将OnePerson
属性设置为Man
或Woman
类型。一个包含所有共享属性的接口将是理想的,因为这样代码就可以访问它的属性,而无需强制转换,并且您可以保留现有的所有绑定
IPerson OnePerson { get; set; }
如果无法使用共享接口,则可以使用对象
,但是,在代码中引用其属性之前,您需要记住将一个人
对象强制转换为男人
或女人
类
object OnePerson { get; set; }
...
if (((Man)OnePerson).Age < 0) ...
不过,您可能需要一些标志来标识哪个是填充的对象,并在更新对象的属性和确定视图的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>
下面是一个使用标志确定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>
总的来说,我建议您要么尝试使OnePerson
成为两个对象共享的数据类型,要么为两个对象创建一个单独的ViewModel
。听起来你们两个班都很相似,所以你们甚至可以