简体   繁体   English

WPF UserControl公开用于绑定的子控件的属性

[英]WPF UserControl exposing properties of subcontrols for binding

I'm working on developing a custom user control for my application. 我正在为我的应用程序开发自定义用户控件。 This control is very simple. 此控件非常简单。 It's just a grid, with a checkbox in [0,0] and a TextBlock in [0,1]. 它只是一个网格,在[0,0]中有一个复选框,在[0,1]中有一个TextBlock。 I've had no issues getting it designed how I'd like in XAML. 我对它在XAML中的设计方式没有任何疑问。

However, the second step is giving me some trouble. 但是,第二步给我带来了一些麻烦。 I'm trying to expose the IsChecked bool? 我正在尝试公开IsChecked布尔值? of my sub-control that is a Checkbox for binding on my mainform, and the same idea with the Text property of TextBlock. 子控件的一部分,该复选框是用于绑定到我的主窗体上的复选框,并且具有与TextBlock的Text属性相同的想法。

I've tried a few different ways of going about this, but to no avail. 我已经尝试了几种不同的方法来解决这个问题,但无济于事。

Here's the general code I have: 这是我的一般代码:

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();
    }
}

When I run the code above, I get no errors, but my binded data doesn't show up in my TextBlock control. 当我运行上面的代码时,没有任何错误,但是绑定的数据没有显示在TextBlock控件中。 When I tried before I wrote the depenency properties, it gave me an error in my XAML saying "A 'Binding' cannot be set on the 'IsChecked' property of type 'CDCheckBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject." 在编写依赖项属性之前进行尝试时,它在XAML中给我一个错误,提示“无法在类型'CDCheckBox'的'IsChecked'属性上设置'Binding'。只能在DependencyProperty上设置'Binding' DependencyObject。”

Interestingly however, this error does not appear in the constructor, but instead in the window_loaded method I've written. 但是有趣的是,此错误并未出现在构造函数中,而是出现在我编写的window_loaded方法中。 This appears to be a red herring however, as if I comment out that code, it still fails before the form can display with XAMLParse Error. 但是,这似乎是一条红色的鲱鱼,就像我注释掉该代码一样,它仍然无法通过表格显示XAMLParse错误。

Further to my comment, you could try styling an existing control that has the property types that you need. 根据我的评论,您可以尝试设计具有所需属性类型的现有控件的样式。 For example, in your custom control you have a nullable Boolean property and a string property. 例如,在自定义控件中,您具有可为null的布尔属性和字符串属性。 If you repurpose a CheckBox control, it already has a nullable Boolean property ( IsChecked ) and an object property ( Content ) which can be used to hold a string. 如果重新使用CheckBox控件,则该CheckBox已经具有可为空的布尔属性( IsChecked )和对象属性( Content ),可用于保存字符串。

Here's how you might restyle a CheckBox control and change its template to achieve the result you're after: 您可以按照以下方式重新设置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>

Key here are the TemplateBinding bindings used in the control template. 此处的关键是控件模板中使用的TemplateBinding绑定。 These bind not to a data context like in normal data binding, but rather to properties of the control being templated. 它们不像普通数据绑定那样绑定到数据上下文,而是绑定到要模板化的控件的属性。

Whenever you find yourself wanting to create a custom control in WPF it is worth exploring whether you can take an existing control and change its appearance to suit what you need, as this is often less work than creating a new control (on the flipside it's not always possible to repurpose an existing control, particularly if you need different behaviour). 每当您发现自己想要在WPF中创建自定义控件时,就值得探索一下是否可以采用现有控件并更改其外观以适合您的需要,因为这通常比创建新控件要少(反之,则不是总是有可能重新利用现有控件的用途,尤其是在您需要其他行为的情况下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM