我有WPF custom Control
,其中包含ComboBox
。我想通过ItemsSource
将此ComboBox的Dependency Property
绑定到自定义控件类的CollectionViewSource
,但我无法弄清楚如何使CollectionViewSource识别正确DataContext
(我的自定义控件属性,在本例中)。
我google了很多,阅读了几乎所有SO自定义控件\ CollectionViewSource \ Collection绑定\依赖属性绑定\等。问题并尝试了一些类似问题的解决方案,例如this one和this以及some more,但仍然无效。我可能会错过一些东西,但我不知道是什么。
以下是Custom Control类的相关部分:
public class CustomComboBox : Control
{
static CustomComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomComboBox), new FrameworkPropertyMetadata(typeof(CustomComboBox)));
}
public CustomComboBox()
{
CustomItems = new ObservableCollection<ComboBoxItem>();
DataContext = this;
}
internal ObservableCollection<ComboBoxItem> CustomItems
{
get { return (ObservableCollection<ComboBoxItem>)GetValue(CustomItemsProperty); }
set { SetValue(CustomItemsProperty, value); }
}
// Using a DependencyProperty as the backing store for CustomItems. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomItemsProperty =
DependencyProperty.Register("CustomItems", typeof(ObservableCollection<ComboBoxItem>), typeof(CustomComboBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
private string text;
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged("Text");
}
}
// More properties, events and functions...
}
以及xaml代码的相关部分:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
x:Class="CustomComboBox">
<CollectionViewSource x:Key="GroupedData"
Source="{Binding Path=CustomItems, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CustomComboBox}, diag:PresentationTraceSources.TraceLevel=High}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="GroupName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<!-- ...Some more Styles and DataTemplates... -->
<Style TargetType="{x:Type local:CustomComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomComboBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ComboBox IsEditable="True"
Text="{Binding Text}"
ItemsSource="{Binding Source={StaticResource GroupedData}}">
<!-- ...Some more properties... -->
</ComboBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
我从System.Diagnostics
获得此输出:
System.Windows.Data警告:58:路径:'CustomItems'
System.Windows.Data警告:60:BindingExpression(hash = 28932383):默认模式已解析为OneWay
System.Windows.Data警告:61:BindingExpression(hash = 28932383):解析为PropertyChanged的默认更新触发器
System.Windows.Data警告:62:BindingExpression(hash = 28932383):附加到System.Windows.Data.CollectionViewSource.Source(hash = 23914501)
System.Windows.Data警告:66:BindingExpression(hash = 28932383):RelativeSource(FindAncestor)需要树上下文
System.Windows.Data警告:65:BindingExpression(hash = 28932383):解析源延迟
System.Windows.Data警告:67:BindingExpression(hash = 28932383):解析源
System.Windows.Data警告:70:BindingExpression(hash = 28932383):找到数据上下文元素:(确定)
System.Windows.Data警告:67:BindingExpression(hash = 28932383):解析源
System.Windows.Data警告:70:BindingExpression(hash = 28932383):找到数据上下文元素:(确定)
System.Windows.Data警告:67:BindingExpression(hash = 28932383):解析来源(最后机会)
System.Windows.Data警告:70:BindingExpression(hash = 28932383):找到数据上下文元素:(确定)
System.Windows.Data错误:4:无法找到绑定源,引用'RelativeSource FindAncestor,AncestorType ='MyNamespace.CustomComboBox',AncestorLevel ='1''。 BindingExpression:路径= CustomItems;的DataItem = NULL; target元素是'CollectionViewSource'(HashCode = 23914501); target属性是'Source'(类型'Object')
我首先尝试了这种绑定:
<CollectionViewSource x:Key="GroupedData"
Source="{Binding CustomItems}">
然后我收到错误:
System.Windows.Data错误:2:找不到管理FrameworkElement 或目标元素的FrameworkContentElement。 BindingExpression:路径= CustomItems;的DataItem = NULL;目标元素是 'CollectionViewSource'(HashCode = 37908782);目标属性是 '来源'(输入'对象')
BTW-将ComboBox内部绑定到另一个属性 - 就像Text
绑定一样。
答案 0 :(得分:5)
虽然@ KyloRen的答案通常是正确的(Inheritance Context特别有用),但我想提供替代解决方案。关键点是,有问题的CollectionViewSource
应该被定义为FrameworkElement
作为模板可视树的一部分的资源(在我看来,一个很好的选择是根元素) 。这是模板:
<ControlTemplate TargetType="{x:Type local:CustomComboBox}">
<Border (...)>
<Border.Resources>
<CollectionViewSource x:Key="GroupedData"
Source="{Binding CustomItems, RelativeSource={RelativeSource TemplatedParent}}">
(...)
</CollectionViewSource>
</Border.Resources>
<ComboBox IsEditable="True"
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}"
ItemsSource="{Binding Source={StaticResource GroupedData}}">
(...)
</ComboBox>
</Border>
</ControlTemplate>
以下是此解决方案的一些优点:
DataContext
- 独立的,它允许您在任何数据上下文中使用它而不会破坏控件的功能请注意,虽然后者是真的,但您应该修改模板中的绑定以使用RelativeSource={RelativeSource TemplatedParent}
(或在适用的情况下使用TemplateBinding
)。另外,我建议从构造函数中删除DataContext = this;
行,因为它会阻止数据上下文继承。
答案 1 :(得分:2)
我在你的代码中看到了一些问题,为什么你这样设计?但是我会跳过所有这一部分( 你必须有这样的理由 ,例如设置DataContext
,初始化CustomItems
等等。并只需编辑XAML
即可使其正常运行。要使Binding
工作,您需要了解WPF
中Inheritance Context的概念。谷歌,你会发现很多关于它的东西。据我所知,我改变了你的代码如下:
<local:CustomComboBox>
<local:CustomComboBox.Resources>
<CollectionViewSource x:Key="GroupedData"
Source="{Binding Path=CustomItems}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="GroupName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</local:CustomComboBox.Resources>
<local:CustomComboBox.Style>
<Style TargetType="{x:Type local:CustomComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomComboBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ComboBox IsEditable="True"
Text="{Binding Text}"
ItemsSource="{Binding Source={StaticResource GroupedData}}">
</ComboBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:CustomComboBox.Style>
</local:CustomComboBox>
它有效。以上并不完美,但 我只是进行了微小的更改 (更改结构和绑定)以使上述代码正常工作。同时将DataSource
添加为:
public CustomComboBox()
{
CustomItems = new ObservableCollection<ComboBoxItem>();
CustomItems.Add(new ComboBoxItem() { Content = "4" });
CustomItems.Add(new ComboBoxItem() { Content = "5" });
DataContext = this;
}
<强> 输出: 强>
答案 2 :(得分:1)
我在这里创建了一个解决方案:https://github.com/orhtun/WPFCustomControlBinding
我故意保持它非常简单,没有View Models,GroupedData(如你的例子中所示)等。如果我的问题出错了,请发表评论,我会尽力解决它:)
用法就是这样;
<wpfCustomControlBinding:CustomControl Grid.Row="0" Grid.Column="0" CustomItems="{Binding DataStringList}"></wpfCustomControlBinding:CustomControl>