【问题标题】:WPF UserControl exposing properties of subcontrols for bindingWPF UserControl 公开子控件的属性以进行绑定
【发布时间】:2015-04-01 15:52:31
【问题描述】:

我正在为我的应用程序开发自定义用户控件。这个控制非常简单。它只是一个网格,在 [0,0] 中有一个复选框,在 [0,1] 中有一个 TextBlock。在 XAML 中按照我想要的方式设计它没有任何问题。

但是,第二步给我带来了一些麻烦。我试图公开 IsChecked 布尔值?我的子控件是一个复选框,用于绑定到我的主窗体上,与 TextBlock 的 Text 属性相同。

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

这是我的通用代码:

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 中给出了一个错误,提示“无法在 'CDCheckBox' 类型的 'IsChecked' 属性上设置 'Binding'。只能在 DependencyProperty 上设置'Binding'一个 DependencyObject。”

然而有趣的是,这个错误并没有出现在构造函数中,而是出现在我编写的 window_loaded 方法中。然而,这似乎是一个红鲱鱼,就好像我注释掉该代码一样,它仍然会在表单显示 XAMLParse 错误之前失败。

【问题讨论】:

  • 提示:输入 propdp 并按两次 TAB 键以生成正确的依赖属性。你的不正确。
  • 哦,有趣...谢谢。很高兴知道。
  • @Sypher_04 您是否想过简单地重新设置现有控件的样式,而不是创建一个全新的控件。听起来您只需要一个布尔值(用于复选框)和一个字符串(用于 TextBlock),因此您可以重新设置CheckBox 控件的样式并将其模板更改为包含Grid、内部CheckBox 和@ 987654327@。详情请见MSDN
  • @Steven Rands 我实际上并没有考虑从主窗体中重新设计样式。我的绑定都以这种方式完美地工作。但是,不幸的是,它确实给我带来了一个不同的问题。我已将此添加到我的原始帖子中。
  • 更新已删除。我意识到这只是我在与星期一的案件作斗争。当我做了一个调整时,我没有想清楚。现在一切似乎都在工作。感谢您的帮助。 :)

标签: c# wpf xaml binding user-controls


【解决方案1】:

根据我的评论,您可以尝试为具有所需属性类型的现有控件设置样式。例如,在您的自定义控件中,您有一个可为空的布尔属性和一个字符串属性。如果您重新调整 CheckBox 控件的用途,它已经有一个可为空的布尔属性 (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 中创建自定义控件时,值得探索是否可以采用现有控件并更改其外观以适合您的需要,因为这通常比创建新控件的工作少(在另一方面,重新调整现有控件的用途并不总是可能的,尤其是当您需要不同的行为时。

【讨论】:

  • 非常有趣的是,您是如何做到这一点的,而我最终是如何做到这一点的。这干净多了。一个问题......我如何扩展这个概念以使 CheckBox 具有固定宽度,而 TextBlock 填充剩余空间,但最多只能达到总宽度。例如,CheckBox = 30,TextBlock = 100,总共 130。TextBlock 然后会将其内容包装在这些限制内。
  • @Sypher_04 使用DockPanel 作为控件模板中的容器,而不是示例中的Grid。然后将复选框停靠在左侧,让文本块占据剩余空间。
  • 这实际上并没有回答所提出的问题。 OP 询问如何公开子控件属性以进行绑定。简单地告诉他们找到另一个已经公开了他们需要的属性的控件可能会解决这个单一的实例,但是当他们需要制作一个没有适应性类似物的控件时会发生什么?
猜你喜欢
  • 2011-05-09
  • 1970-01-01
  • 2013-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-31
相关资源
最近更新 更多