【问题标题】:WPF - What conditions must be met to use data binding in a custom control's content items?WPF - 必须满足哪些条件才能在自定义控件的内容项中使用数据绑定?
【发布时间】:2009-04-27 20:36:30
【问题描述】:

我正在制作自定义控件——特别是饼图。我希望标记看起来像这个例子:

<c:PieChart>
    <!-- These dependency properties are never set -->
    <c:Slice Value="{Binding RedCount}" />
    <c:Slice Value="{Binding BlueCount}" />
    <c:Slice Value="{Binding GreenCount}" />
</c:PieChart>

PieChart 派生自Control

[ContentProperty("Slices")]
public class PieChart : Control
{
    public PieChart()
    {
        Slices = new ObservableCollection<Slice>();
    }

    public ObservableCollection<Slice> Slices { get; private set; }
}

上述 XAML 导致 Slices 属性填充了三个 Slice 实例。

这是来自Slice的sn-p:

public class Slice : ContentControl
{
    public static DependencyProperty ValueProperty
        = DependencyProperty.Register(
            "Value", typeof(double), typeof(Slice),
            new PropertyMetadata((p,a) => ((Slice)p).OnValueChanged(a)));

    private void OnValueChanged(DependencyPropertyChangedEventArgs e)
    {
        // This code never called!
    }
}

问题是 Slice 上的 Value 属性从未设置。如果我将依赖属性放在PieChart 上并复制绑定表达式,则值已设置,因此我确信我了解依赖属性和绑定的基础知识。

那么,我必须做些什么才能让我的依赖属性为子项设置一个值?由于这些项目在我自己的收藏中,它们是否不在逻辑树中,任何魔法都可以使绑定起作用?

一个简单的“这样做”答案会有所帮助,但我真的很想了解这里出了什么问题,所以我会接受发布的最具洞察力、解释性的答案。

编辑我没有说清楚,但是在PieChartDataContext 上有一些环境对象,其中包含属性RedCount 等。过去,当我'在绑定路径中有错字(或其他错误) 我在运行时在 VS 输出窗口中看到了警告。在这种情况下,我什么也看不到。

【问题讨论】:

    标签: wpf binding dependency-properties


    【解决方案1】:

    看起来Slice 控件没有连接到可视化树。它们只是成员变量,WPF 并不知道将它们显示为PieChart 的子元素。几种可能的方法:

    PieChart 调用AddLogicalChild 添加Slice 对象。您将需要处理在运行时将Slices 添加到集合中或从集合中删除的可能性。这是相当低的级别:MSDN 建议,“对于控件作者,不推荐在此级别操作逻辑树,除非可用基本控件类的内容模型都不适合您的控件方案。考虑在该级别进行子类化ContentControlItemsControlHeaderedItemsControl。”

    PieChart 设为Panel。然后Slices 将成为它的孩子,但请注意Children 属性是弱类型的,因此人们可以向PieChart 添加任何内容。这本质上不是一件坏事或一件好事。这是一个设计考虑(见下面的注释)。但这可能不是您想要的。

    PieChart 设为ItemsControl,并覆盖GetContainerForItemOverrideIsItemItsOwnContainerOverride 和可能的PrepareContainerForItemOverride 以创建/尊重Slice 控件。 (参见ListBoxListBoxItemComboBoxComboBoxItem 等)其中一个很好的功能是用户可以使用 ItemsSourceDataTemplate(如 ListBox)代替必须手动创建子控件。 (但用户仍然可以根据您的语法在 XAML 中创建固定的 Slices,就像他们可以在 XAML 中创建 ListBoxItems 一样。)

    您甚至可以考虑采用混合方法,例如将径向布局功能分解为RadialLayoutPanel,将饼图生成分解为ItemsControl,它使用RadialLayoutPanel 作为其ItemsPanel

    【讨论】:

      【解决方案2】:

      我认为您看到的问题是绑定试图使用错误的源。我怀疑这样的事情会为你工作:

      <c:PieChart>
          <!-- These dependency properties are never set -->
          <c:Slice Value="{Binding RedCount, RelativeSource={AncestorType c:PieChart}}" />
          <c:Slice Value="{Binding BlueCount, RelativeSource={AncestorType c:PieChart}}" />
          <c:Slice Value="{Binding GreenCount, RelativeSource={AncestorType c:PieChart}}" />
      </c:PieChart>
      

      我认为这很接近,但我可能还差得很远。我现在真的查不出来。但这对我来说听起来不错。 (对不起,如果完全错误:))

      【讨论】:

      • 再次阅读问题后,我不认为这些值首先来自 PieChart 类......这使得这完全没有意义。不客气。
      • 挑剔点——我认为应该是 {Binding RelativeSource={RelativeSource AncestorType...}} (即您需要在 RelativeSource 表达式中重复 RelativeSource)。是的,我知道很烦人。
      • 谢谢,但不,属性是在一些环境数据上下文对象上定义的。如果绑定失败,我会在 VS 输出窗口中看到警告消息,但没有显示。我将编辑帖子以提及这一点。
      猜你喜欢
      • 2020-03-07
      • 1970-01-01
      • 2014-06-24
      • 2015-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-04
      相关资源
      最近更新 更多