2013-08-04 59 views
4

如何將數據綁定到只有getter而沒有setter的數據從wpf中的視圖模型訪問它?我正在與PasswordBox合作,並希望將其SecureString屬性綁定到ViewModel屬性。我怎樣才能做到這一點?數據綁定屬性沒有設置器

+0

要綁定到你的視圖模型一個只讀屬性? –

+0

我是wpf和mvvm的新手。我想在我的viewmodel中獲得密碼的安全字符串,並且不會設置它。 –

+0

你的問題是'PasswordBox'控件上的'SecureString'屬性是隻讀屬性,這意味着你不能從標記或代碼中設置。 –

回答

0

綁定在XAML:

<PasswordBox Text="{Binding SecureString, Mode=OneWay}"... 

,如果你不希望它從XAML綁定

public string SecureString 
{ 
    get { return _secureString;} 
    private set 
    { 
     if(_secureString == value) return; 
     _secureString = value; 
     RaisePropertyChanged(() => SecureString); 
    } 

public void SetSecureString(string newSecureString) 
{ 
    SecureString = newSecureString; 
} 

改變您的視圖模型的消費者應該能夠設置SecureString雖然這種方法..

1

我使用這個類和System.Windows.Interactivity庫來訪問沒有setter的屬性:

public sealed class PropertyManager : TriggerAction<FrameworkElement> 
{ 
    #region Fields 

    private bool _bindingUpdating; 
    private PropertyInfo _currentProperty; 
    private bool _propertyUpdating; 

    #endregion 

    #region Dependency properties 

    /// <summary> 
    ///  Identifies the <see cref="Binding" /> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty BindingProperty = 
     DependencyProperty.Register("Binding", typeof(object), typeof(PropertyManager), 
      new PropertyMetadata((o, args) => 
      { 
       var propertyManager = o as PropertyManager; 
       if (propertyManager == null || 
        args.OldValue == args.NewValue) return; 
       propertyManager.TrySetProperty(args.NewValue); 
      })); 

    /// <summary> 
    ///  Identifies the <see cref="SourceProperty" /> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty SourcePropertyProperty = 
     DependencyProperty.Register("SourceProperty", typeof(string), typeof(PropertyManager), 
      new PropertyMetadata(default(string))); 

    /// <summary> 
    ///  Binding for property <see cref="SourceProperty" />. 
    /// </summary> 
    public object Binding 
    { 
     get { return GetValue(BindingProperty); } 
     set { SetValue(BindingProperty, value); } 
    } 

    /// <summary> 
    ///  Name property to bind. 
    /// </summary> 
    public string SourceProperty 
    { 
     get { return (string)GetValue(SourcePropertyProperty); } 
     set { SetValue(SourcePropertyProperty, value); } 
    } 

    #endregion 

    #region Methods 

    /// <summary> 
    ///  Invokes the action. 
    /// </summary> 
    /// <param name="parameter"> 
    ///  The parameter to the action. If the action does not require a parameter, the parameter may be 
    ///  set to a null reference. 
    /// </param> 
    protected override void Invoke(object parameter) 
    { 
     TrySetBinding(); 
    } 

    /// <summary> 
    ///  Tries to set binding value. 
    /// </summary> 
    private void TrySetBinding() 
    { 
     if (_propertyUpdating) return; 
     PropertyInfo propertyInfo = GetPropertyInfo(); 
     if (propertyInfo == null) return; 
     if (!propertyInfo.CanRead) 
      return; 
     _bindingUpdating = true; 
     try 
     { 
      Binding = propertyInfo.GetValue(AssociatedObject, null); 
     } 
     finally 
     { 
      _bindingUpdating = false; 
     } 
    } 

    /// <summary> 
    ///  Tries to set property value. 
    /// </summary> 
    private void TrySetProperty(object value) 
    { 
     if (_bindingUpdating) return; 
     PropertyInfo propertyInfo = GetPropertyInfo(); 
     if (propertyInfo == null) return; 
     if (!propertyInfo.CanWrite) 
      return; 
     _propertyUpdating = true; 
     try 
     { 
      propertyInfo.SetValue(AssociatedObject, value, null); 
     } 
     finally 
     { 
      _propertyUpdating = false; 
     } 
    } 

    private PropertyInfo GetPropertyInfo() 
    { 
     if (_currentProperty != null && _currentProperty.Name == SourceProperty) 
      return _currentProperty; 
     if (AssociatedObject == null) 
      throw new NullReferenceException("AssociatedObject is null."); 
     if (string.IsNullOrEmpty(SourceProperty)) 
      throw new NullReferenceException("SourceProperty is null."); 
     _currentProperty = AssociatedObject 
      .GetType() 
      .GetProperty(SourceProperty); 
     if (_currentProperty == null) 
      throw new NullReferenceException("Property not found in associated object, property name: " + 
               SourceProperty); 
     return _currentProperty; 
    } 

    #endregion 
} 

要使用這個類在XAML您需要添加到System.Windows.Interactivity庫的引用,並添加這個命名空間:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:behaviors="clr-namespace:YOUR NAMESPACE WHERE YOU PUT THE PropertyManager CLASS" 

您還需要指定要更新值的情況下,在這種情況下PasswordChanged,並指定要綁定的屬性,在這種情況下Password

<PasswordBox> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="PasswordChanged"> 
      <behaviors:PropertyManager 
       Binding="{Binding Path=MyPasswordProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
       SourceProperty="Password" /> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</PasswordBox> 

這個類是通用的,可以與任何性質的工作還支持雙向綁定。

+0

棒極了!我沒有使用這個密碼箱,但@Victor Mukherjee問了一個很好的問題,甚至不知道它,你的答案是非常好的。 –

+0

我有點嫉妒,誰寫的PropertyManager類? –

0

您可以通過設置binding modeOneWayGet only property結合你的綁定 -

<PasswordBox Text="{Binding SecureString, Mode=OneWay}"