wpf 没有 setter 的属性上的数据绑定
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18043877/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DataBinding on properties with no setter
提问by Victor Mukherjee
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 PasswordBoxand want to bind its SecureStringproperty to a ViewModel property. How can I do that?
如何将数据绑定到只有 getter 而没有 setter 的属性以从 wpf 中的视图模型访问它?我正在使用PasswordBox并希望将其SecureString属性绑定到 ViewModel 属性。我怎样才能做到这一点?
回答by Vyacheslav Volkov
I use this class and the System.Windows.Interactivitylibrary to get access for properties with no setter:
我使用这个类和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
}
To use this class in XAML you need to add a reference to System.Windows.Interactivity library and add this namespaces:
要在 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"
You also need to specify the event that will be updated value, in this case PasswordChangedand specify a property that you want to bind, in this case Password:
您还需要指定将更新值的事件,在本例中,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>
This class is versatile and can work with any of the properties also supports two-way binding.
这个类是通用的,可以与任何属性一起使用,还支持双向绑定。
回答by Rohit Vats
You can bind with Get only propertyby setting the binding modeto OneWayon your binding -
您可以Get only property通过将绑定模式设置为绑定来OneWay绑定 -
<PasswordBox Text="{Binding SecureString, Mode=OneWay}"
回答by denis morozov
bind in xaml:
在 xaml 中绑定:
<PasswordBox Text="{Binding SecureString, Mode=OneWay}"...
if you don't want it changed from xaml binding
如果您不希望它从 xaml 绑定更改
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 SecureStringthough that method..
您的 ViewModel 的使用者应该能够SecureString通过该方法设置..

