我要实现的目的是以分组方式将ViewModel(mvvm light)对象的属性绑定到一些自制的自定义控件上。
所以我创建了一个CustomControl1,它具有Title属性和我自己的自定义类型SomeDataControl的ItemsCollection。
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(string), typeof(CustomControl1), new PropertyMetadata(default(string)));
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public ObservableCollection<SomeDataControl> _ItemsCollection;
public ObservableCollection<SomeDataControl> ItemsCollection {
get
{
if(_ItemsCollection == null) _ItemsCollection = new ObservableCollection<SomeDataControl>();
return _ItemsCollection;
}
}
}
public class SomeDataControl : DependencyObject
{
public static readonly DependencyProperty LAbelProperty = DependencyProperty.Register(
"LAbel", typeof(string), typeof(SomeDataControl), new PropertyMetadata(default(string)));
public string LAbel
{
get { return (string) GetValue(LAbelProperty); }
set { SetValue(LAbelProperty, value); }
}
public static readonly DependencyProperty DValueProperty = DependencyProperty.Register(
"DValue", typeof(double), typeof(SomeDataControl), new PropertyMetadata(default(double)));
public double DValue
{
get { return (double) GetValue(DValueProperty); }
set { SetValue(DValueProperty, value); }
}
}
我还添加了一个样式,将控件的内容呈现到ItemsControl中,并将值绑定到这样的适当字段:
<Style x:Key="ControlStyle" TargetType="local:CustomControl1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<Label Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text}"></Label>
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemsCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=LAbel}" />
<Label Content="{Binding Path=DValue}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
然后我将所有这些都使用DataContext视图模型放入我的视图中,这样我就可以达到这些值。
<Window x:Class="BindingTest.MainWindow" x:Name="thisControl" DataContext="{Binding Source={StaticResource Locator}, Path=VM}">
...
<local:CustomControl1 Text="{Binding Path=DataContext.Text, ElementName=thisControl}" Style="{StaticResource ControlStyle}" >
<local:CustomControl1.ItemsCollection>
<local:SomeDataControl LAbel="Apple" DValue="{Binding Path=DataContext.DVal1, Mode=TwoWay, ElementName=thisControl}">
<local:SomeDataControl LAbel="Peach" DValue="{Binding Path=DataContext.DVal2, Mode=TwoWay, ElementName=thisControl}">
<local:SomeDataControl LAbel="Pear" DValue="{Binding Path=DataContext.DVal3, Mode=TwoWay, ElementName=thisControl}"></local:SomeDataControl>
</local:CustomControl1.ItemsCollection>
</local:CustomControl1>
一切顺利,直到我想将DVal1,2和3绑定到特定项目。它们都是默认值。 我已经在寻找答案已有3天了,但是找不到任何有帮助的方法。我也尝试使用DependenyProperty进行收集,或将其类型更改为Freezable的简单列表,但没有任何帮助。
我真的很想在XAML中以这种方式声明组,而不是将所有内容放到ViewModel中以到达布局。
任何一种帮助都是很好的。
谢谢。
答案 0 :(得分:0)
问题是你的束缚
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=LAbel}" />
<Label Content="{Binding Path=DValue}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>``
在构建Itemsource集合时无法意识到
<local:CustomControl1.ItemsCollection>
<local:SomeDataControl LAbel="Apple" DValue="{Binding Path=DataContext.DVal1, Mode=TwoWay, ElementName=thisControl}">
<local:SomeDataControl LAbel="Peach" DValue="{Binding Path=DataContext.DVal2, Mode=TwoWay, ElementName=thisControl}">
<local:SomeDataControl LAbel="Pear" DValue="{Binding Path=DataContext.DVal3, Mode=TwoWay, ElementName=thisControl}"></local:SomeDataControl>
</local:CustomControl1.ItemsCollection>
当您第一次创建SomeDataControl时,Style需要一个项目源,但是直到到达结束标记后才可用。
因此,如果您不想在Viewmodel中,请在窗口的“资源”部分中创建itemsource并将其绑定到customControl。
<Window.Resources>
<x:Array x:Key="Mycollection" Type="local:SomeDataControl">
<local:SomeDataControl LAbel="Apple"
DValue="{Binding Path=DataContext.DVal1, Mode=TwoWay}"/>
<local:SomeDataControl LAbel="Peach"
DValue="{Binding Path=DataContext.DVal2, Mode=TwoWay}"/>
</x:Array>
</Window.Resources>
并绑定到收藏集
<local:CustomControl1.ItemsCollection ItemsSource={StaticResource Mycollection}/>
答案 1 :(得分:0)
实际上,我通过使用提示和一些谷歌搜索找到了答案。 主要问题是,我的SomeDataControl项不是可视化树的一部分,因此它们没有获得更高级别FrameworkElement的数据上下文。 所以我对这篇文章介绍了一个绑定代理:
所以我的XAML看起来像这样:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
<local:BindingProxy x:Key="proxy" Data="{Binding}" />
</ResourceDictionary>
</Window.Resources>
...
<local:SomeDataControl LAbel="Apple" DValue="{Binding Path=Data.DVal1, Source={StaticResource proxy}}"></local:SomeDataControl>
并且绑定代理的代码也非常好用,很容易,值得重新共享:
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object) GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
链接的博客文章中也有一些解释
解决我们问题的方法实际上非常简单,并且利用了Freezable类。此类的主要目的是定义具有可修改状态和只读状态的对象,但是在我们的案例中,有趣的功能是,即使Freezable对象不在可视树或逻辑树中,它们也可以继承DataContext。 / p>
谢谢大家的支持。