WPF UserControl 公开子控件的属性以进行绑定

WPF UserControl exposing properties of subcontrols for binding

我正在为我的应用程序开发自定义用户控件。这个控件非常简单。它只是一个网格,在 [0,0] 中有一个复选框,在 [0,1] 中有一个 TextBlock。我在 XAML.

中按照自己喜欢的方式设计它没有遇到任何问题

然而,第二步却给我带来了一些麻烦。我正在尝试公开 IsChecked 布尔值?我的子控件是一个用于绑定到我的主窗体上的复选框,与 TextBlock.

的文本 属性 的想法相同

我尝试了几种不同的方法来解决这个问题,但都无济于事。

这是我的通用代码:

public partial class CDCheckBox : UserControl
{
    public bool? IsChecked
    {
        get { return chk.IsChecked; }
        set { chk.IsChecked = value; }
    }

    public string Text
    {
        get { return lbl.Text; }
        set { lbl.Text = value; }
    }

    public static readonly DependencyProperty IsCheckedProperty =
    DependencyProperty.Register(
        "IsChecked",
        typeof(bool?),
        typeof(CDCheckBox),
        new PropertyMetadata(default(bool?), OnItemsPropertyChanged));

    public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register(
        "Text",
        typeof(string),
        typeof(CDCheckBox),
        new PropertyMetadata(default(string), OnItemsPropertyChanged));

    /*
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnNotify(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
    */
    private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // AutocompleteTextBox source = d as AutocompleteTextBox;
        // Do something...
        //lbl.Text = e.NewValue.ToString();
    }

    /*
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnNotify(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
    */

    public CDCheckBox()
    {
        InitializeComponent();
    }
}

当我 运行 上面的代码时,我没有收到任何错误,但我的绑定数据没有显示在我的 TextBlock 控件中。当我在写依赖属性之前尝试时,它在我的 XAML 中给了我一个错误,说 "A 'Binding' cannot be set on the 'IsChecked' property of type 'CDCheckBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject."

然而有趣的是,这个错误并没有出现在构造函数中,而是出现在我编写的 window_loaded 方法中。然而,这似乎是一个转移注意力的问题,就好像我注释掉了该代码一样,在表单可以显示 XAMLParse Error.

之前它仍然失败

根据我的评论,您可以尝试设置具有您需要的 属性 类型的现有控件的样式。例如,在您的自定义控件中,您有一个可为 null 的布尔值 属性 和一个字符串 属性。如果重新调整 CheckBox 控件的用途,它已经有一个可为 null 的布尔值 属性 (IsChecked) 和一个对象 属性 (Content),可用于保存一个字符串。

您可以按照以下方式重新设置 CheckBox 控件的样式并更改其模板以获得您想要的结果:

<Window x:Class="..."
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Window.Resources>
        <Style x:Key="MySuperCheckboxStyle"
               TargetType="{x:Type CheckBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type CheckBox}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
                            <CheckBox Grid.Column="0"
                                      IsChecked="{TemplateBinding IsChecked}"
                                      Content="Whatever you need here" />
                            <TextBlock Grid.Column="1"
                                       Text="{TemplateBinding Content}" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <StackPanel>
        <CheckBox IsChecked="True"
                  Content="Unstyled check box"
                  Margin="10" />
        <CheckBox Style="{StaticResource MySuperCheckboxStyle}"
                  IsChecked="True"
                  Content="Styled check box"
                  Margin="10" />
    </StackPanel>
</Window>

这里的关键是 TemplateBinding 控件模板中使用的绑定。它们不像普通数据绑定那样绑定到数据上下文,而是绑定到被模板化的控件的属性。

每当您发现自己想要在 WPF 中创建自定义控件时,都值得探索是否可以使用现有控件并更改其外观以满足您的需要,因为这通常比创建新控件更省事(另一方面,并​​不总是可以重新调整现有控件的用途,尤其是当您需要不同的行为时)。