有没有办法以编程方式绑定到输入绑定命令属性?

时间:2013-10-29 21:13:46

标签: c# wpf xaml mvvm

我知道这是一个通用标题,但我的问题是具体的。我认为这将归结为一个实践问题。所以,我有以下代码:

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);

1 个答案:

答案 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>