繁体   English   中英

WPF:使用MVVM时更改数据绑定

[英]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}将正确评估,而不管OnePersonMan还是Woman对象,并且将显示该对象上任何Age属性的值。

因此,最好的解决方案是将OnePerson属性设置为可以是ManWoman 包含所有共享属性的接口将是理想的,因为这样它的属性可以被代码访问而无需强制转换,并且您可以保留所有已经拥有的绑定。

IPerson OnePerson { get; set; }

如果无法使用共享接口,而只能使用object ,那么您需要记住在代码中引用OnePerson对象到ManWoman类之前, OnePerson转换为ManWoman类。

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> ,在其中将ManWoman传递为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM