2011-06-10 135 views
4

我有一個在XAML中聲明的視圖(請參見下文)。關聯的視圖模型是使用MEF自動創建的。我希望能夠做這樣的事情:從XAML設置ViewModel屬性值

<local:MyControl Owner={x:Static local:Owners.ProjectOwner} /> 

所需的淨效應是對於一些視圖模型屬性被設置等於Owners.ProjectOwner。

我可以使用hacky代碼隱藏實現所需的結果,但寧願通過綁定或類似的方式來實現。任何人都可以提出一種做法嗎?

UPDATE

我順從地寫行爲。但我並沒有把所有的努力都放在一個具體的案例上,而是將我的解決方案通用化了,我把它列入下面,以防任何人感興趣。這是Blend行爲(System.Windows.Interactivity.dll),但可以很容易地成爲傳統的附加行爲。

using System; 
using System.Windows; 
using System.Windows.Interactivity; 

namespace BlendBehaviors 
{ 
    public class SetViewModelPropertyBehavior : Behavior<FrameworkElement> 
    { 
     public static readonly DependencyProperty PropertyNameProperty = 
      DependencyProperty.Register("PropertyName", typeof(string), typeof(SetViewModelPropertyBehavior)); 

     public static readonly DependencyProperty PropertyValueProperty = 
      DependencyProperty.Register("PropertyValue", typeof(object), typeof(SetViewModelPropertyBehavior)); 

     public SetViewModelPropertyBehavior() 
     { } 

     public string PropertyName 
     { 
      get { return (string)GetValue(PropertyNameProperty); } 
      set { SetValue(PropertyNameProperty, value); } 
     } 

     public object PropertyValue 
     { 
      get { return GetValue(PropertyValueProperty); } 
      set { SetValue(PropertyValueProperty, value); } 
     } 

     protected override void OnAttached() 
     { 
      base.OnAttached(); 
      var ao = AssociatedObject; 
      SetViewModel(ao.DataContext); 
      ao.DataContextChanged += FrameworkElement_DataContextChanged; 
     } 

     protected override void OnDetaching() 
     { 
      base.OnDetaching(); 
      AssociatedObject.DataContextChanged -= FrameworkElement_DataContextChanged; 
     } 

     private void FrameworkElement_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) 
     { 
      SetViewModel(e.NewValue); 
     } 

     private void SetViewModel(object viewModel) 
     { 
      SetViewModelProperty(viewModel, PropertyName, PropertyValue); 
     } 

     private static void SetViewModelProperty(object viewModel, string propertyName, object propertyValue) 
     { 
      if (viewModel == null || propertyName == null) { 
       return; 
      } 
      var info = viewModel.GetType().GetProperty(propertyName); 
      if (info != null && CanAssignValue(propertyValue, info.PropertyType)) { 
       info.SetValue(viewModel, propertyValue, null); 
      } 
     } 

     private static bool CanAssignValue(object value, Type targetType) 
     { 
      if (value == null) { 
       return !targetType.IsValueType || Nullable.GetUnderlyingType(targetType) != null; 
      } 
      return targetType.IsAssignableFrom(value.GetType()); 
     } 
    } 
} 

然後使用它是這樣的:

<local:MyControl> 
    <i:Interaction.Behaviors> 
     <bb:SetViewModelPropertyBehavior PropertyName="Owner" PropertyValue="{x:Static local:Owners.ProjectOwner}" /> 
     <bb:SetViewModelPropertyBehavior PropertyName="AnotherProperty" PropertyValue="{StaticResource MyResourceKey}" /> 
    </i:Interaction.Behaviors> 
</local:MyControl> 

回答

3

任何WPF的結合必須是DependencyProperty目標。源可以是DependencyProperty,實現INotifyPropertyChanged的CLR對象,或者只是一些對象。目標和來源可以通過更改Binding.Mode屬性進行交換。

但是在這種情況下,綁定中的其中一項是靜態解析的屬性(Owners.ProjectOwner)。因此,這不是DependencyProperty。因此,它只能作爲來源出現。因此,你綁定到的(目標)必須是DependencyProperty。因此,它不可能是您的視圖模型的屬性(假設您尚未創建基於DependencyObject的視圖模型,這將是a mistake)。

因此,您不能直接將虛擬機上的屬性綁定到靜態屬性。你可以寫一個附加的行爲,雖然這爲你做。

+0

我理解並同意你所說的一切。我不一定要在MyControl上聲明一個名爲「Owner」的DependencyProperty - 示例代碼僅僅是說明性的。我可以編寫一個附加的行爲,但希望在第一個實例中解決這個問題,而不使用對視圖模型的強類型引用。會考慮這個並回到你身邊。 – 2011-06-10 08:52:09

+1

我最終實現了Blend行爲:請參閱我的更新。感謝您的貢獻。 – 2011-06-10 15:35:55