【问题标题】:How to create a Dependency Property for Binding如何为绑定创建依赖属性
【发布时间】:2017-06-06 14:52:18
【问题描述】:

我正在处理一个“简单”的案例。我喜欢创建一个实现 DependencyProperty 的新自定义控件。在下一步中,我想创建一个绑定来更新两个方向的属性。我为此案例构建了一个简单的示例,但绑定似乎不起作用。我找到了一种使用 FrameworkPropertyMetadata 更新 DPControl 属性的方法,但我不知道使用 OnPropertyChanged 事件是否也是一个好主意。

这里是我的示例项目:

我的控件只包含一个标签

<UserControl x:Class="WPF_MVVM_ListBoxMultiSelection.DPControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPF_MVVM_ListBoxMultiSelection"
             mc:Ignorable="d" Height="84.062" Width="159.641">
    <Grid Margin="0,0,229,268">
        <Label Content="TEST" x:Name="label" Margin="0,0,-221,-102"/>
    </Grid>
</UserControl>

并实现自定义依赖属性。目前,我还为 FramePropertyMetadata 实现了 PropertyChanged 方法,并在该方法中设置了标签的内容,但我喜欢让它双向工作。

public partial class DPControl : UserControl
{
    public DPControl()
    {
        InitializeComponent();
    }

    public string MyCustomLabelContent
    {
        get { return (string)GetValue(MyCustomLabelContentProperty);}
        set
        {
            SetValue(MyCustomLabelContentProperty, value);
        }
    }

    private static void OnMyCustomLabelContentPropertyChanged(DependencyObject source,
    DependencyPropertyChangedEventArgs e)
    {
        DPControl control = (DPControl)source;
        control.label.Content = e.NewValue;
    }

    public static readonly DependencyProperty MyCustomLabelContentProperty = DependencyProperty.Register(
          "MyCustomLabelContent",
          typeof(string),
          typeof(DPControl),
          new FrameworkPropertyMetadata(null,
              OnMyCustomLabelContentPropertyChanged
          )
        );

我只是在一个窗口中使用这个控件:

<local:DPControl MyCustomLabelContent="{Binding MyLabelContent, Mode=TwoWay}" Margin="72,201,286,34"/>

MyLabelContent 是 ViewModel 中的一个属性,它也实现了 INotifyPropertyChanged 接口。

public class ViewModel_MainWindow:NotifyPropertyChanged
{

    private string _myLabelContent;

    public string MyLabelContent
    {
        get { return _myLabelContent; }
        set { _myLabelContent = value;
            RaisePropertyChanged();
        }
    }...

那么我怎样才能让它工作:在自定义属性上使用绑定功能和我的新控件。

【问题讨论】:

    标签: c# wpf data-binding dependency-properties


    【解决方案1】:

    在您的用户控件中:

    <Label 
        Content="{Binding MyCustomLabelContent, RelativeSource={RelativeSource AncestorType=UserControl}}"
        x:Name="label" Margin="0,0,-221,-102"/>
    

    并摆脱该属性更改的回调。您所需要的只是绑定。

    我喜欢让它双向工作

    默认情况下使依赖属性为双向:

    public static readonly DependencyProperty MyCustomLabelContentProperty = 
        DependencyProperty.Register(
            "MyCustomLabelContent",
            typeof(string),
            typeof(DPControl),
            new FrameworkPropertyMetadata(null, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
        );
    

    我省略了不必要的属性更改处理程序。

    现在它不能是双向的,因为Label.Content 不能生成它自己的值。如果您希望您的 UserControl 在其代码隐藏中设置值,这很容易:

    MyCustomLabelContent = "Some arbitrary value";
    

    如果您像我向您展示的那样进行绑定,这将更新 UserControl XAML 中的 Label 以及绑定到 UserControl 的依赖项属性的 viewmodel 属性。

    如果您希望 XAML 设置它,您需要

    最后,这个:

    Margin="0,0,-221,-102"
    

    不是做布局的好方法。带有GridStackPanel 等的 WPF 布局更简单、更健壮。

    【讨论】:

    • 谢谢,这适用于简单的情况,但现在我喜欢为列表框实现一个包装用户控件来获取 ItemsSelected,但它不起作用。关于这个案例有什么提示吗?
    • @Kinimod ItemsSelected 很痛苦:你无法绑定它。它也是一个集合,因此您必须处理更改通知。那是另一个问题。
    • 你说得对,这很痛苦。对另一个第三方控件处理列表有什么建议,比如列表框,它有一个用于绑定的 SelectedItems 列表?
    • @Kinimod 我处理过的唯一第三方 WPF 控件是 DevExpress 和 Infragistics,我不太关心其中任何一个。我认为这里的答案中有一个附加属性/行为,可以让你绑定 SelectedItems。我可能在某个地方有类似的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-06
    • 2016-01-22
    • 2012-11-08
    • 2012-08-01
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多