How can I bind data to a property with only a getter and no setter to access it from view model in wpf? I am working with PasswordBox and want to bind its SecureString property to a ViewModel property. How can I do that?
            Asked
            
        
        
            Active
            
        
            Viewed 8,917 times
        
    5
            
            
         
    
    
        Victor Mukherjee
        
- 10,487
- 16
- 54
- 97
- 
                    You want to bind to a read-only property on your view-model ? – Ibrahim Najjar Aug 04 '13 at 14:17
- 
                    I am new to wpf and mvvm. I want to get the securestring of the password in my viewmodel and would not be setting it. – Victor Mukherjee Aug 04 '13 at 14:19
- 
                    Your problem is that the `SecureString` property on the `PasswordBox` control is a read-only property, meaning you can not set not from markup nor from code. – Ibrahim Najjar Aug 04 '13 at 14:26
- 
                    Do you want to let the `PasswordBox` set a property of type `SecureString` on your view-model from XAML ? – Ibrahim Najjar Aug 04 '13 at 14:29
- 
                    2Did you read [this](http://stackoverflow.com/questions/1483892/how-to-bind-to-a-passwordbox-in-mvvm)? – Vyacheslav Volkov Aug 04 '13 at 14:32
- 
                    yes, that is exactly what i am looking for. I want to retrieve the password user enters in my view model. – Victor Mukherjee Aug 04 '13 at 14:32
3 Answers
2
            
            
        I use this class and the System.Windows.Interactivity library to get access for properties with no 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
}
To use this class in XAML you need to add a reference to System.Windows.Interactivity library and add this namespaces:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviors="clr-namespace:YOUR NAMESPACE WHERE YOU PUT THE PropertyManager CLASS"
You also need to specify the event that will be updated value, in this case PasswordChanged and specify a property that you want to bind, in this case 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>
This class is versatile and can work with any of the properties also supports two-way binding.
 
    
    
        Vyacheslav Volkov
        
- 4,592
- 1
- 20
- 20
- 
                    Superb ! I am not using this for PasswordBox, but the @Victor Mukherjee asked a very good question without even knowing it, and your answer is very good. – Raiden Core Feb 10 '17 at 02:59
- 
                    
0
            
            
        bind in xaml:
<PasswordBox Text="{Binding SecureString, Mode=OneWay}"...
if you don't want it changed from xaml binding
public string SecureString
{
   get { return _secureString;}
   private set
   {
      if(_secureString == value) return;
      _secureString = value;
      RaisePropertyChanged(() => SecureString);
   }
 public void SetSecureString(string newSecureString)
 {
     SecureString = newSecureString;
 }
the consumer of your ViewModel should be able to set SecureString though that method..
 
    
    
        denis morozov
        
- 6,236
- 3
- 30
- 45
0
            
            
        You can bind with Get only property by setting the binding mode to OneWay on your binding -
<PasswordBox Text="{Binding SecureString, Mode=OneWay}"
 
    
    
        Rohit Vats
        
- 79,502
- 12
- 161
- 185