[英]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.