【问题标题】:Binding Dependency Properties to Custom Controls将依赖属性绑定到自定义控件
【发布时间】:2014-08-07 19:56:06
【问题描述】:

我正在开发一个大量使用数据网格的 WPF 应用程序。我有一个经常出现的情况,需要我在数据网格中使用自定义控件。当然,每一行绑定的数据都不一样。

我解决这个问题的方法是制作一个 DataGridTemplateColumn 类型的自定义控件,并向其中添加我自己的依赖项属性。然后当我需要在我的网格中使用这种列类型时,我可以在一行中完成。

自定义控件的数据上下文似乎完全不正常。

现在,我有以下代码...

DataGridCheckedComboColumn.xaml

<DataGridTemplateColumn x:Class="DataTracker.Presentation.GridControls.Views.DataGridCheckedComboColumn"
                        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:ccb="clr-namespace:CheckedComboBoxControl;assembly=CheckedComboBox"
                        mc:Ignorable="d">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ccb:CheckedComboBox ItemsSource="{Binding Path=ComboSource}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ccb:CheckedComboBox ItemsSource="{Binding Path=ComboSource}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

这用于后面的代码......

DataGridCheckedComboColumn.xaml.cs

namespace DataTracker.Presentation.GridControls.Views
{
    /// <summary>
    /// Interaction logic for DataGridCheckedComboColumn.xaml
    /// </summary>
    public partial class DataGridCheckedComboColumn : DataGridTemplateColumn
    {
        public DataGridCheckedComboColumn()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Gets or sets the runway data.
        /// </summary>
        /// <value>The runway data.</value>
        public IEnumerable<Object> ComboSource
        {
            get
            {
                return (IEnumerable<Object>)this.GetValue(ComboSourceProperty);
            }
            set
            {
                this.SetValue(ComboSourceProperty, value);
            }
        }

        private static void OnComboSourceChanged(DependencyObject dependentView, DependencyPropertyChangedEventArgs e)
        {
            /////////////////////////////////////////////////////////////////
            //                                                             //
            // This is the code I used when I was making user controls and //
            // sending data to the view models                             //
            //                                                             //
            //                                                             //
            // Not sure what, if anything to do here now...                //
            //                                                             //
            /////////////////////////////////////////////////////////////////

            //var control = (DataGridComboColumn)dependentView;
            //var viewModel = (DataGridComboColumnViewModel)control.DataContext;

            //viewModel.ComboSource = (IEnumerable<Object>)e.NewValue;
        }

        public static readonly DependencyProperty ComboSourceProperty =
            DependencyProperty.Register("ComboSource",
                typeof(IEnumerable<Object>),
                typeof(DataGridCheckedComboColumn),
                new FrameworkPropertyMetadata()
                {
                    PropertyChangedCallback = OnComboSourceChanged,
                    BindsTwoWayByDefault = true
                });

    }
}

我像这样将自定义控件添加到我的数据网格中......

<gc:DataGridCheckedComboColumn ComboSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}, Path=DataContext.DataVersions}" />

一切都正确呈现,但无论我通过什么数据,都没有成功。我什至对列表进行了硬编码并发送了这些列表,但没有运气。我也尝试过发送其他简单的属性,比如字符串,但也失败了。

WPF 给出以下错误。我应该指出,“GenericGridObject”是我用来填充完整数据网格的内容。

System.Windows.Data Error: 40 : BindingExpression path error: 'ComboSource' property not found on 'object' ''GenericGridObject`1' (HashCode=37030675)'. BindingExpression:Path=ComboSource; DataItem='GenericGridObject`1' (HashCode=37030675); target element is 'CheckedComboBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')

就像我之前说的,我认为这是自定义控件的数据上下文的问题,但我似乎无法弄清楚如何强制它使用自己的类作为数据上下文而不是数据上下文整个网格。

有什么想法吗?

【问题讨论】:

  • 如果您尝试重新创建此控件以查看我在说什么,您只需将 更改为 还是会出现同样的问题。
  • 我认为问题在于您正在绑定到不知道 Dependancy 属性的 DataContext。我认为您需要绑定到 DataGridTemplateColumn ,您可以使用相对源来执行此操作。见stackoverflow.com/questions/1636807/…
  • 如果我尝试命名根元素 (DataGridTemplateColumn),然后使用 ,我会收到一条错误消息。 ...“System.Windows.Data 错误:4:找不到与引用'ElementName = myName'的绑定源”。另外 VS 中出现错误说...“无法在此范围内注册重复的名称 'myName'。”

标签: c# wpf xaml wpf-controls custom-controls


【解决方案1】:

我遇到了数据上下文不继承的类似问题,我使用此处描述的代理技术解决了我的问题http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

更新:

尝试在 DataGridCheckedComboColumn 中添加相对源

<ccb:CheckedComboBox ItemsSource="{Binding Path=ComboSource, RelativeSource={RelativeSource AncestorType=ccb:DataGridCheckedComboColumn}"

由于没有指定控件中的 Datacontext,我猜它会采用其父级的 Datacontext。如果这不起作用,因为 DataTemplates 与 DataGridTemplateColumn 不在同一逻辑或可视树中,则使用代理思想,以便

<DataGridTemplateColumn x:Class="DataTracker.Presentation.GridControls.Views.DataGridCheckedComboColumn"
                        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:ccb="clr-namespace:CheckedComboBoxControl;assembly=CheckedComboBox"
                        mc:Ignorable="d">
            <DataGridTemplateColumn .Resources>
                <ccb:BindingProxy x:Key="proxy" Data="{Binding RelativeSource={RelativeSource AncestorType=ccb:DataGridCheckedComboColumn}}" />
            </DataGridTemplateColumn .Resources>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ccb:CheckedComboBox ItemsSource="{Binding Path=Data.ComboSource, Source={StaticResource proxy}}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ccb:CheckedComboBox ItemsSource="{Binding Path=Data.ComboSource, Source={StaticResource proxy}}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

【讨论】:

  • 这看起来很有希望,但我似乎找不到将资源添加到仅列的方法。请记住,我的控件只是一个 DataGridTemplateColumn,它独立于使用它的实际数据网格而存在。
  • 所以datagrid中的每一行对于CheckedComboBox可以有不同的itemsource,这个itemsource是由datagrid itemssource DataVersions属性决定的?
  • 没有。网格中的每一行都由一个项目源填充。这反过来填充了我为网格定义的所有列。此外,每个记录的选中组合框将填充所有相同的数据(至少在此示例中,某些实现将需要不同的记录集)。问题是,选中的组合框的数据没有通过绑定到自定义控件。
  • 考虑到这一点,它仍然说明了同样的问题。例如,用一个简单的按钮替换选中的组合框。将 IEnumerable 依赖属性更改为字符串类型。如果您尝试将该字符串依赖属性绑定到自定义控件中按钮的内容,它仍然会以相同的方式中断。如果它是字符串并且我执行了 ,则绑定仍然会中断并且不会显示在按钮的内容中。我通过依赖属性发送的任何数据都不会通过绑定。
  • 我在我的答案中添加了更新,并提供了一些尝试建议。
猜你喜欢
  • 2012-08-29
  • 1970-01-01
  • 2012-08-07
  • 2019-05-26
  • 2021-08-17
  • 2011-05-08
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多