C# 不使用setter在属性上进行数据绑定

C# 不使用setter在属性上进行数据绑定,c#,wpf,data-binding,mvvm,C#,Wpf,Data Binding,Mvvm,如何将数据绑定到只有getter而没有setter的属性,以便从wpf中的视图模型访问它?我正在使用PasswordBox并希望将其SecureString属性绑定到ViewModel属性。如何才能做到这一点?在xaml中绑定: <PasswordBox Text="{Binding SecureString, Mode=OneWay}"... ViewModel的使用者应该能够通过该方法设置SecureString。我使用此类和库来访问属性,而无需设置器: public sealed

如何将数据绑定到只有getter而没有setter的属性,以便从wpf中的视图模型访问它?我正在使用
PasswordBox
并希望将其
SecureString
属性绑定到ViewModel属性。如何才能做到这一点?

在xaml中绑定:

<PasswordBox Text="{Binding SecureString, Mode=OneWay}"...
ViewModel的使用者应该能够通过该方法设置
SecureString

我使用此类和库来访问属性,而无需设置器:

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
}
您还需要指定将被更新的事件值,在本例中为
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>


此类用途广泛,可与任何属性一起使用,还支持双向绑定。

通过将绑定上的设置为“单向”,可以使用
Get only属性进行绑定-

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

是否要绑定到视图模型上的只读属性?我是wpf和mvvm的新手。我想在我的viewmodel中获取密码的securestring,但不会对其进行设置。您的问题是
PasswordBox
控件上的
securestring
属性是只读属性,这意味着您不能从标记或代码进行设置。是否要让
密码框
从XAML在视图模型上设置类型为
SecureString
的属性?阅读了吗?非常好!我不是用这个作为密码箱,但是@Victor Mukherjee在不知情的情况下问了一个很好的问题,你的回答很好。我有点嫉妒,谁写了PropertyManager类?
<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>
<PasswordBox Text="{Binding SecureString, Mode=OneWay}"