如何从两个不同的属性创建依赖项属性

本文关键字:属性 创建 依赖 两个 | 更新日期: 2023-09-27 18:34:12

我有UserControl属性,看起来像这样:

public string Text
{
    get
    {
        return string.Format("{0}:{1}", Text1, Text2);
    }
    set
    {
        var array = value.Split(':');
        Text1 = array[0];
        Text2 = array[1];
    }
}

请注意,Text1Text2 是来自两个TextBox控件的文本。现在我需要将此属性转换为 DependencyProperty但本文说我应该避免在 get 和 set 定义中采用任何逻辑,以便我可以将我的 get 和 set 逻辑放在哪里,或者我如何以不同的方式执行此操作?

编辑
所以我在这里有三个类似的答案,但Value Changed Callback只解决了来自set而不是get的代码。仅当我从代码设置属性时才使用此代码有效,但在更改Text1Text2时无效。

编辑 2
我想使用此新DependencyProperty作为TwoWay绑定的目标。

如何从两个不同的属性创建依赖项属性

您可以尝试创建依赖属性,并在 PropertyChangedCallBack 中执行拆分逻辑。让我知道这是否可以解决您的问题

 public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(MyClass), new PropertyMetadata(string.Empty,valueChanged));
        private static void valueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MyClass c = d as MyClass;
            if(c!=null)
            {
                var array = e.NewValue.ToString().Split(':');
                c.Text1 = array[0];
                c.Text2 = array[1];
            }
        }

在 WPF 中,对于DependencyProperty,属性的 Sseters 和 Getters 很少被调用(WPF 通常使用 DependencyObjectSetValueGetValue 方法)。

为了在值更改时"执行"任何操作,您可以在DependencyPropertyFrameworkMetadata中提供一个PropertyChangedCallback

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text", typeof (string), typeof (ColorPicker), new PropertyMetadata(default(string), OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = d as UserControl;
    if (null == control) return; // This should not be possible
    var newValue = e.NewValue as string;
    if (null == newValue) return;
    var split = newValue.Split(':');
    control.Text1 = split.ElementAtOrDefault(0);
    control.Text2 = split.ElementAtOrDefault(1);
}
public string Text
{
    get { return (string) GetValue(TextProperty); }
    set { SetValue(TextProperty, value); }
}

请注意,"OnTextChanged"方法是静态的,您必须"手动"将 DependencyObject 转换为控件的类型。(将var control = d as UserControl替换为控件类型)。

您的整个用户控件将如下所示:

public partial class MyUserControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();
    }
    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl), 
        new PropertyMetadata(new PropertyChangedCallback(OnTextChanged)));
    private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var myControl = d as MyUserControl;
        if (null != myControl)
        {
           var newValue = e.NewValue as string;
           if (null != newValue)
           {
                var split = newValue.Split(':');
                myControl.Text1 = split[0];
                myControl.Text2 = split[1];
           }
        }
    }
    public string Text1 { get; set; }
    public string Text2 { get; set; }
}

可以使用普通依赖项属性并分配绑定到两个文本框的文本属性的多重绑定。

一、依赖属性声明:

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text", typeof(string), typeof(UserControl1));
public string Text
{
    get { return (string)GetValue(TextProperty); }
    set { SetValue(TextProperty, value); }
}

现在,您必须创建一个要与多重绑定一起使用的转换器类。转换器执行字符串拆分和连接逻辑(顺便说一句,对于任意数量的子字符串):

class TextConverter : IMultiValueConverter
{
    public object Convert(
        object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return string.Join(":", values);
    }
    public object[] ConvertBack(
        object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return ((string)value).Split(':');
    }
}

最后,创建多重绑定并将其应用于 UserControl 构造函数中的 Text 属性:

public UserControl1()
{
    InitializeComponent();
    var binding = new MultiBinding
    {
        Converter = new TextConverter(),
        Mode = BindingMode.TwoWay
    };
    binding.Bindings.Add(new Binding
    {
        Source = textBox1,
        Path = new PropertyPath("Text"),
        Mode = BindingMode.TwoWay
    });
    binding.Bindings.Add(new Binding
    {
        Source = textBox2,
        Path = new PropertyPath("Text"),
        Mode = BindingMode.TwoWay
    });
    SetBinding(TextProperty, binding);
}

此解决方案的缺点是,对 Text 属性的任何其他绑定(例如,代码中的其他位置,使用控件的位置)都将替换 MultiBinding。但是,您始终可以将 Text 属性用作与另一个元素的属性的双向绑定中的源属性。