如何通过附加的属性

时间:2017-05-10 18:49:50

标签: c# wpf xaml binding

我有一个名为TxtBox的类,其附加属性:

public class TxtBox
{
    public static readonly DependencyProperty TypeProperty = DependencyProperty.RegisterAttached(
        "Type", typeof (Enums.FieldType), typeof (TextBox), new PropertyMetadata(default(Enums.FieldType),OnTypeChanged));

    public static void SetType(DependencyObject element, Enums.FieldType value)
    {
        element.SetValue(TypeProperty, value);
    }

    public static Enums.FieldType GetType(DependencyObject element)
    {
        return (Enums.FieldType) element.GetValue(TypeProperty);
    }

    private static void OnTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var src = (TextBox) d; //(FrameworkElement)d;
        var binding = BindingOperations.GetBinding(src, TextBox.TextProperty);
        if (binding != null) //Binding here is always null ?????????
        {
            binding.Converter = new NumberConverter();
            binding.ConverterParameter = e.NewValue;
        }
    }
}

在MainWindow.xaml:

<Grid Margin="10">
   <TextBox Text="{Binding RequestNo}"  att:TxtBox.Type="Number" />
<\Grid>

一旦我通过附加属性(Type)设置了文本框控件的类型,我就需要为Converter分配ConverterParameterTextProperty。当OnTypeChanged方法触发时,我无法获得绑定,因为它始终为空!

提前致谢:)

2 个答案:

答案 0 :(得分:0)

在将Binding应用于“文本”框的“文本”属性之前,正在设置附加属性。您可以通过在Text的值更改时尝试更新Binding来解决此问题:

private static void OnTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var src = (TextBox)d;

    var dpd = DependencyPropertyDescriptor.FromProperty(TextBox.TextProperty, typeof(TextBox));

    dpd.AddValueChanged(src, UpdateBindingHandler);

    UpdateBinding(src);
}

protected static void UpdateBindingHandler(object sender, EventArgs e)
{
    UpdateBinding((TextBox)sender);
}

private static void UpdateBinding(TextBox tbox)
{
    var binding = BindingOperations.GetBinding(tbox, TextBox.TextProperty);

    if (binding != null)
    {
        binding.Converter = new NumberConverter();
        binding.ConverterParameter = GetType(tbox);

        var dpd = DependencyPropertyDescriptor.FromProperty(TextBox.TextProperty, typeof(TextBox));

        //  Don't do this every time the value changes, only the first time 
        //  it changes after TxtBox.Type has changed. 
        dpd.RemoveValueChanged(tbox, UpdateBindingHandler);
    }
}

当你这样做时,你会发现你的整个设计存在缺陷:一旦使用Binding,你就无法改变它。它引发了一个例外。

您可以通过创建新绑定,克隆旧绑定的属性以及在其上放置转换器来逃脱。但是,绑定具有很多属性,如果已经有转换器,那么您需要将链接转换器替换为保留转换器的转换器。

我不确定此功能是否会成功。

答案 1 :(得分:0)

最后,我得到了解决方案,我改变了设计,因为Peter Duniho先生建议我写一个标记扩展来代替{Binding}

public class TextBoxTypeExtension:MarkupExtension
    {
        private readonly Binding _binding;
        public TextBoxTypeExtension(Binding binding,Enums.FieldType type)
        {
            _binding = binding;
            _binding.Converter = new NumberConverter();
            _binding.ConverterParameter = type;
        }
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return _binding.ProvideValue(serviceProvider);
        }
    }

在MainWindow.xaml:

  <TextBox  MaxLength="10" Grid.Row="1" Grid.Column="1"
                        Text="{extension:TextBoxType {Binding Request.RequestNo},Number}"/>

<强>参考: MarkupExtension that uses a DataBinding value