我现在正在做一些培训项目。它应该将数字转换为不同的字符串。这是转换后的控件,在主窗口中以底部的方式使用它。所以第一个问题是我想根据我传递给 OutputFormatProperty 的值创建转换器的实例,所以在这种情况下,我创建了应该是 OctalConverter 类型的转换器,但我得到了默认的转换器,为什么会这样?另一件事是,我不想通过将转换器中的 InputValue 绑定到 CurrentValue 来更改它,它适用于 NotifyPropertyChanged,但它似乎不是那样工作的。
public partial class ConverterDisplay : UserControl {
private const int DEFAULT_INPUT_VALUE = 0;
private readonly ObservableCollection <DisplayField> _displayFields;
private AbstractNumberConverter _converter;
public static readonly DependencyProperty InputValueProperty = DependencyProperty.Register (
"InputValue",
typeof(int),
typeof(ConverterDisplay),
new PropertyMetadata (DEFAULT_INPUT_VALUE));
public static readonly DependencyProperty OutputFormatProperty = DependencyProperty.Register (
"OutputFormat",
typeof(NumberSystems),
typeof(ConverterDisplay),
new FrameworkPropertyMetadata (NumberSystems.Binary));
public int InputValue {
get {
return (int) GetValue (InputValueProperty);
}
set {
SetValue (InputValueProperty, value);
UpdateDisplay ();
}
}
public NumberSystems OutputFormat {
get {
return (NumberSystems) GetValue (OutputFormatProperty);
}
set {
SetValue (OutputFormatProperty, value);
}
}
public ObservableCollection <DisplayField> DisplayFields {
get { return _displayFields; }
}
public ConverterDisplay () {
_displayFields = new ObservableCollection<DisplayField> ();
InitializeComponent ();
CreateConverter ();
}
private void UpdateDisplay () {
var convertedNumberString = _converter.GetString (InputValue);
if (_displayFields.Count > convertedNumberString.Length)
ResetDisplayFields ();
while (_displayFields.Count < convertedNumberString.Length)
AddDisplayField ();
UpdateValues (convertedNumberString);
}
private void UpdateValues (string convertedString) {
if (_displayFields.Count == 0) return;
for (int i = 0; i < _displayFields.Count; i++) {
_displayFields [i].NumberValue = convertedString [i];
}
}
private void AddDisplayField () {
_displayFields.Insert (
0,
new DisplayField ((int)OutputFormat, _displayFields.Count));
}
private void ResetDisplayFields () {
_displayFields.Clear ();
}
private void CreateConverter () {
switch (OutputFormat) {
case NumberSystems.Binary:
_converter = new BinaryConverter ();
break;
case NumberSystems.Octal:
_converter = new OctalConverter ();
break;
case NumberSystems.Hexadecimal:
_converter = new HexadecimalConverter ();
break;
}
}
}
public enum NumberSystems {
Binary = 2,
Octal = 8,
Hexadecimal = 16
}
然后在主窗口中,我尝试使用该控件
<converters:ConverterDisplay x:Name="octConverter"
InputValue="{Binding ElementName=Window,Path=CurrentValue}"
OutputFormat="Octal"/>
以防万一
public int CurrentValue {
get { return _currentValue; }
set {
if (value == _currentValue)
return;
ValidateNewValue (value);
OnPropertyChanged ();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
}
====
============================编辑 #1
我不太喜欢那个解决方案,但我在 ConverterDisplay 中创建了公共方法来创建转换器,它在初始化 MainWindow 后被调用,所以现在转换器是正确的。另一件事是如何将我的 UpdateDisplay 方法绑定到 InputValueProperty?我通过验证发现它获得了正确的值,但我看不出如何在不创建静态内容的情况下运行该方法。
关于你的第二个问题(将UpdateDisplay
方法绑定到InputValueProperty
: 通常,在依赖项属性的 setter 中调用任何方法并不是最好的主意,因为在使用数据绑定填充依赖项属性的值时,永远不会调用此 setter,如 MSDN 所述:
WPF XAML 处理器使用属性系统方法实现依赖关系 加载二进制 XAML 和处理以下属性时的属性 依赖项属性。这有效地绕过了属性 包装。实现自定义依赖项属性时,必须 考虑到此行为,并应避免将任何其他代码放入 属性系统方法 GetValue 以外的属性包装器 和设置值。
相反,创建一个每当 InputValue
的内容更改时调用的回调方法,并从那里调用UpdateDisplay
:
public static readonly DependencyProperty InputValueProperty = DependencyProperty.Register (
"InputValue",
typeof(int),
typeof(ConverterDisplay),
new PropertyMetadata (DEFAULT_INPUT_VALUE, InputValueChangedCallback));
private static void InputValueChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var userControl = dependencyObject as ConverterDisplay;
if (userControl != null)
userControl.UpdateDisplay();
}