2013-06-27 30 views
2

以下是我真正想要做的一個簡化示例,但我對它的問題是相同的。WPF:在使用MVVM時更改數據綁定

假設我有兩個對象,男人和女人,他們都有相同的屬性(年齡,身高和體重),但他們是兩個不同的對象。我無法改變這一點。

現在假設我有一個WPF面板,它是使用MVVM原理製作的,它顯示了文本框中某個人的年齡。我爲此使用Text =「{Binding Path = OnePerson.Age}」,其中OnePerson是在視圖模型中定義的Man類型的對象。

這工作正常,但我想要一個類似的頁面來顯示一個女人的這個信息。理想情況下,我想只使用與以前相同的視圖和視圖模型。但這很棘手,因爲數據綁定指向了Man-object OnePerson。我可以以編程方式更改數據綁定(如WPF Binding Programatically中所述),但我只能從視圖的代碼隱藏中這樣做。我不能這麼做,因爲我們使用的是MVVM模型。

我想使OnePerson是指男人或女人的對象,但我不知道這樣做的好方法。他們是不同的類型,所以我不能只使用if語句來指定男人或女人。我可以將OnePerson聲明爲對象而不是類型,但是我無法輕鬆地訪問Age,Height和Weight屬性。或者我可以製作一個完全不同的ViewModel,其中一個將OnePerson聲明爲男人,另一個聲稱爲女人,並對他們使用相同的視圖。我認爲這應該可行,但對於單個視圖有兩個視圖模型似乎有點奇怪。在我開始添加新功能(如添加新的男人/女人或編輯現有的功能)時,添加我自己的Person類並在它與「男人或女人」之間進行轉換可能會使整個視圖模型變得相當複雜,直到我可能以及複製粘貼人視圖和視圖模型並僅將OnePerson對象更改爲女人。

我的問題是,是否有使用單一視圖和視圖模型顯示無論是男人還是在這種情況下,一個女人的信息的乾淨和簡單的方式。或者我應該不打擾併爲這些情況製作單獨的頁面?

希望這已經夠清楚了。

回答

3

我覺得這是對ViewModel更多的問題比查看或綁定。 View僅用於表示ViewModel的視覺表示,聽起來像您的問題需要在ViewModel而不是View中修復。

如果綁定無效,那麼WPF的綁定系統只會發出警告,並且它不關心DataContext的數據類型。無論OnePersonMan還是Woman對象,您的問題({Binding OnePerson.Age})中顯示的綁定都會正確評估,並將顯示該對象上任何Age屬性的值。

因此,最好的解決方案是使OnePerson屬性的類型可以是ManWoman。一個包含所有共享屬性的接口將是理想的,因爲它的屬性可以被代碼訪問而不需要轉換,並且可以保留所有已有的綁定。

IPerson OnePerson { get; set; } 

如果這是不可能使用一個共享的界面比你可以使用一個object,但是你需要記住引用它在代碼屬性之前的OnePerson對象轉換爲ManWoman類。

object OnePerson { get; set; } 

... 

if (((Man)OnePerson).Age < 0) ... 

第二種替代方案是創建兩個單獨的性質,一個用於Man,一個用於Woman。然後,您可以通過ViewModel輕鬆訪問正在處理的任何項目的屬性,並且可以使用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還是要分開的模板爲每個對象類型,你可以輕鬆地用somethi像隱含的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>,在那裏你在ManWomanT

+0

謝謝你的解釋廣泛年齡屬性只是工作。我自己考慮過DataTriggers,但看起來像是一旦遇到更復雜的面板,它會很快變得麻煩。但Datatemplate示例看起來不錯。我明天會試一試。 – user2527902

1

您是否想過基於Interfaced對象創建對象?界面基本上創建了一個合同,聲明從它派生的任何東西必須具有它至少聲明的任何東西......派生控件可以有更多,但至少是你想要的東西。例如。

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(); 

希望這爲您的實施選擇打開了一些門。

+0

謝謝你的建議通過。不幸的是,關於如何定義我在實際案例中使用的對象,我可以做的並不多。 (他們是AchterstandswijkRootCollection EN GrenswijkRootCollection。你可以看到爲什麼我者優先在我的例子簡單的男人和女人。)他們是現有項目的一部分,我不能跟他們一起去搞混。雖然他們是非常深跌的基礎上,同一個接口的對象,我必須要經過我不能提取公用接口對象的任何有意義的信息這麼多怪異的步驟。 – user2527902

+0

@ user2527902,你可以隨時添加另一個接口,並將其添加到現有的類定義。沒有其他人知道他們,它不應該崩潰任何東西。你只是加入它,然後綁定到你想要的那些新簡化的屬性......可能是工作? – DRapp

+0

它可能。但在開始編輯這些內容之前,我必須先徵得許可。這基本上是我的第一個真正的任務,所以我不需要自信地開始改變框架的東西,因爲本質上是一個可選的快捷方式。 – user2527902

0

,如果你只是想用一個XAML控制你的年齡,你可以做

ageusercontrol

<TextBlock Text="{Binding Path=Age}" /> 

personview

<local:AgeUserControl DataContext="{Binding Path=MyObjectTypePersonProperty} /> 
+0

這門課程的時候每個MyObjectTypePersonProperty有 – blindmeis