簡體   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