2010-06-22 26 views
2

我的ViewModel是我的View的DataContext的依賴項屬性。 ViewModel沒有參考視圖。 ViewModel上的屬性將引用視圖上的控件,但我需要能夠在XAML中設置此屬性。從WPF中的視圖設置ViewModel屬性

這怎麼可能?我想過是開發具有財產屬性和價值屬性的自定義控制,所以你可以做這樣的事情在視圖上設置視圖模型屬性:

<PropertySetter Property="{Binding MyViewModelDependencyProperty}" Value="{Binding ElementName=aControlOnMyView" /> 

之前,我去了這路線,我想檢查是否有其他方法可以採取?


感謝您的詳細答覆雷,但如果我給你約我試圖解決這個問題更詳細一點,你可能會得到我爲什麼說我做了該辦法的一個更好的主意。

基本上,我想要做的就是當用戶點擊按鈕時將焦點設置爲文本框。我寫了一個附加屬性,您可以附加到Button控件,指定觸發事件是什麼(在本例中爲「Click」事件),然後指定要關注的控件。這非常好用,並將所有內容保存在XAML中。

但是,我現在有一個用例,應該將焦點設置爲一個任意文本框,作爲工具欄一部分按鈕上的click事件。這個工具欄本身就是一個用戶控件,它坐落在另一個用戶控件內的另一個用戶控件中!這個工具欄需要可以在各種不同的表單中重複使用,每次單擊按鈕後,用於設置焦點的控件在每個表單上都會有所不同。

這就是爲什麼我想讓視圖模型本身(在我的ViewModel基礎上)的焦點控制(即文本框)屬性,並有ViewModel基本代碼(工具欄綁定到),單擊按鈕時將焦點設置到控件上(例如,在ViewModel基礎上調用Add/Edit方法)。

在單元測試用地中,專注於屬性的控件將爲null,因此它的.Focus()方法不會被調用。所以我在那裏看不到問題。我的問題是如何從XAML設置焦點控制屬性,這就是爲什麼我有PropertySetter的想法。

我不喜歡ViewModel對坐在視圖上的控件有任何引用的事實,但我看不到另一種方式來實現我所需要的。如果決定是否將重點放在控制上的邏輯非常複雜?這肯定會在ViewModel中?因此,ViewModel擁有這個UIElement屬性會有什麼危害嗎?它仍然不知道它所綁定的具體視圖,它只知道在ViewModel上發生某些操作時需要將焦點設置爲一個控件。

回答

7

我的第一反應(這是一個強烈的反應)是這麼說的:「不要那樣做!」通過給你的視圖模型提供一部分用戶界面的參考,你正在打破視圖模型如此強大和有用的封裝。

例如,如果您想單元測試您的視圖模型或將其序列化到磁盤會發生什麼?在每種情況下,您的用戶界面將不會出現,因爲根本沒有任何視圖。您的測試將錯過報道,並且您的重組將不完整。

如果您的視圖模型實際上需要對UI對象的引用,並且沒有更好的方法來構建它,最好的解決方案是讓視圖模型本身構造它需要引用的控件。然後,您的視圖可以通過綁定將該控件合併爲ContentPresenter的內容,並提供一個Style來配置該控件,包括一個ControlTemplate以提供其內容。正是如此:

public class MyViewModel 
{ 
    public ListBox SpecialControl { get; set; } 
    public MyViewModel() 
    { 
    SpecialControl = new ListBox(); 
    } 
} 

<DataTemplate TargetType="{x:Type local:MyViewModel}"> 
    <DataTemplate.Resources> 
    <Style TargetType="ListBox" ... /> 
    </DataTemplate.Resources> 
    ... 
    <ContentPresenter Content="{Binding SpecialControl}" /> 
</DataTemplate> 

其他可能性:

  1. 有視圖模式實際上從Control類派生,然後覆蓋OnApplyTemplate(),並使用GetTemplateChild找到模板其名稱以「PART_」開頭的項目
  2. 實現一個帶有屬性名稱的附加屬性,在DataContext中查找該屬性,並將其設置爲屬性附加到的DependencyObject。
  3. 實現你PropertySetter想法

我的選項#2是這樣的:

<DataTemplate TargetType="{x:Type MyViewModel}"> 
    ... 
    <TextBox local:PropertyHelper.SetViewModelToThis="SpecialControl" /> 
    ... 
</DataTemplate> 

在SetViewModelToThis PropertyChangedCallback的代碼會從DataContext的獲取視圖模型,反映在其上找到「SpecialControl」屬性,然後將其設置爲TextBox。請注意,SetViewModelToThis的實現必須考慮到DataContext沒有立即設置的可能性,並且可能需要將舊設置刪除並更改新設置。

2

首先,控件的DataContext應該是ViewModel對象,而不是它的屬性。其次,當您的TwoWayViewModel的屬性綁定到您的控件時,控件值的更改將更新(在您的情況中爲'set')值爲ViewModel的屬性。