我知道这是一个通用标题,但我的问题是具体的。我认为这将归结为一个实践问题。所以,我有以下代码:
public partial class MainWindow : Window
{
InitializeComponent();
MyViewModel viewModel = new MyViewModel();
this.myGrid.DataContext = viewModel;
}
public class MyViewModel
{
public ICommand SomeCommandProperty { get { return this.someCommandProperty; }}
}
public class ComponentCollection : Panel
{
public ComponentCollection()
{
for (int i = 0; i < n; i++)
{
this.Children.Add(new Component());
}
}
}
public class Component : UIElement
{
public Component()
{
this.InputBindings.Add(new MouseBinding(SomeCommandProperty, new MouseGesture(MouseAction.LeftClick)));
}
}
我可以轻松地将拥有SomeCommandProperty的ViewModel聚合到Component类中,但我现在正在放弃该选项,假设还有其他方法。
Component是ComponentCollection的子节点,它是Grid的子节点,DataContext是MyViewModel。 ComponentCollection顾名思义包含一组Components。
<Grid Name="myGrid">
<someNamespace:ComponentCollection x:Name="componentCollection"/>
</Grid>
这与下面的XAML相同,但使用TextBlock。我想我正试图以编程方式复制下面的XAML中所做的事情。同样,Component的最顶级祖先的DataContext设置为ViewModel。
<Grid Name="myGrid">
<TextBlock Text="SomeText">
<TextBlock.InputBindings>
<MouseBinding Command="{Binding SomeCommandProperty}" MouseAction="LeftClick" />
</TextBlock.InputBindings>
</TextBlock>
</Grid>
更新1
基本上,我有一个自定义控件,它从Panel继承,子控件是Component的集合。这不是一个黑客,就像我提到的,我可以直接访问 SomeCommandProperty 如果我将ViewModel聚合到Component中。但是,这样做会让人感觉很蠢。也就是说,可以从Model中直接访问ViewModel。
我想我问的问题是。鉴于Component的父UIElement的DataContext设置为MyViewModel的情况,是否可以访问 SomeCommandProperty 而不使用 组件 拥有对的引用拥有 SomeCommandProperty 的 MyViewModel ?以编程方式,即。
使用ItemsControl不会改变我仍然需要将SomeCommandProperty绑定到每个Items的事实。
更新2
见上面的代码。
更新3
显然,我所知道的机制不会在InputBinding的Command属性上设置绑定。
例如,如果我的Component类是从ButtonBase而不是UIElement继承的话,那么我将使用FrameWorkElement的SetBinding轻松地设置绑定以编程方式的Command属性。不幸的是,我无法使用InputBinding的Command属性执行此操作。
public class Component : ButtonBase
{
public Component()
{
System.Windows.Data.Binding binding = new System.Windows.Data.Binding
{
RelativeSource = new System.Windows.Data.RelativeSource(System.Windows.Data.RelativeSourceMode.FindAncestor, typeof(ComponentCollection), 1 ),
Path = new PropertyPath("DataContext.SomeCommandProperty")
};
// I can do this.
this.SetBinding(this.CommandProperty, binding);
// But I want to do something like below. Note: It's a pseudo code.
MouseBinding mouseBinding = new MouseBinding();
mouseBinding.SetBinding(mouseBinding.CommandProperty, binding);
this.InputBindings.Add(mouseBinding);
}
}
更新4
BindingOperations.SetBinding可用于无法直接访问SetBinding的对象。
解决方案
MouseBinding mouseBinding = new MouseBinding();
BindingOperations.SetBinding(mouseBinding, MouseBinding.CommandProperty, binding);
this.InputBindings.Add(mouseBinding);
答案 0 :(得分:0)
为此使用ItemsControl。当有内置类已经完成此操作时,不要试图自己一起破解。
您还可以使用RelativeSource绑定从Visual Tree中的父UI元素访问ViewModel:
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="SomeText">
<TextBlock.InputBindings>
<!-- See how I'm using RelativeSource to get a hold of the DataContext of the parent ItemsControl -->
<MouseBinding Command="{Binding DataContext.SomeCommandProperty,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"
MouseAction="LeftClick" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>