将DataGridCell ContextMenu MenuItem绑定到ViewModel上的命令

时间:2014-10-02 18:18:10

标签: c# wpf mvvm

我知道SO上也有类似的问题。

我已经审查了他们,尝试了他们,尝试了他们的组合,并在过去的一天重试了他们,但收效甚微。我显然很密集或缺少某些东西。

所涵盖的基本方法是:

  • 展示位置目标
  • 在父级上使用标记属性
  • 使用Ancestor Relative Source
  • 为DataContext使用ElementName root

似乎没有什么工作,只有一个例子我甚至能够在测试转换器中找到一个断点,看看什么是绑定的。它只能在DataCell的Tag属性中工作。我很生气。这跟我一样接近:

<xcdg:DataGridControl.Resources>
    <Style TargetType="{x:Type xcdg:DataCell}">
        <Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding RelativeSource={RelativeSource AncestorType={ x:Type xcdg:DataCell}}, Path=Tag, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>                        
            </Style>
 </xcdg:DataGridControl.Resources>

作为这种方法的变体,我认为标签属性上的绑定有效,并且我可以在DataContext中使用ContextMenu或者甚至只是MenuItem本身。

<ContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" StaysOpen="True"> 

<MenuItem  Header="Acknowledge" DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" Command="{Binding Path=AcknowledgeViolationCommand}"  />

接下来我还尝试了PlacementTarget.DataContext和PlacementTarget.Tag没有结果。

        <Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding PlacementTarget, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>     

其他尝试:

        <Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType={ x:Type v:RTCA}}, Converter={StaticResource TestConverter}}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding PlacementTarget, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem DataContext="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=DataContext}"  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>                        

在这里,我尝试以不同的方式使用ElementName根方法,但它只适用于Cell的Tag,而不适用于ContextMenu的DataContext或Tag

        <Setter Property="Tag" Value="{Binding DataContext, ElementName=root}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding PlacementTarget, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=PacementTarget.Tag.AcknowledgeViolationCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource TestConverter}}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>         

<!-- variation of above --> 
        <Setter Property="Tag" Value="{Binding DataContext, ElementName=root}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Mode=Self}, Path=PlacementTarget.DataContext, Converter={StaticResource TestConverter}}" StaysOpen="True">
                            <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>                        

<Setter Property="ContextMenu">
                        <Setter.Value>
                            <ContextMenu DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource TestConverter}}" StaysOpen="True">
                                <MenuItem Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                            </ContextMenu>
                        </Setter.Value>
                    </Setter>

我可以列出无数失败的尝试。 PlacementTargets,Tags,Ancestors,RelativeSources,为什么我不能做这个工作?为什么我只能在使用DataCell Tag Binding而没有其他地方时才进入我的TestConverter?

继承转换方法:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }

当它触发Tag绑定时,我实际上可以看到ViewModel正如我想要的那样传递,我甚至可以从即时窗口执行我的命令。坦率地说,我的智慧结束了应该是15分钟的事情。

谁能告诉我我做错了什么?

其他示例 来自Lee O.评论我尝试了BindingProxy方法而没有任何运气。

<xcdg:DataGridControl.Resources>
                <vl:BindingProxy x:Key="proxy" Data="{Binding }" />
                <Style TargetType="{x:Type xcdg:DataCell}">
<Setter Property="ContextMenu">
                        <Setter.Value>
                            <ContextMenu DataContext="{StaticResource proxy}" StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                            </ContextMenu>
                        </Setter.Value>
                    </Setter>
                </Style>

其他尝试。接下来的这些尝试确实做了一些新事现在,至少在应用程序启动时,AcknowledgeViolationCommand的断点将触发一次。但是,从上下文菜单中选择项目仍然无效。

<ContextMenu DataContext="{Binding Data, Source={StaticResource proxy}}" StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=AcknowledgeViolationCommand}"  />
                            </ContextMenu>

<ContextMenu StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=Data.AcknowledgeViolationCommand, Source={StaticResource proxy}}"  />
                            </ContextMenu>

也试过x:参考以下内容:

<Setter Property="ContextMenu">
                        <Setter.Value>
                            <ContextMenu StaysOpen="True">
                                <MenuItem  Header="Acknowledge" Command="{Binding Path=DataContext.AcknowledgeViolationCommand, Source={x:Reference dummyControl}, Converter={StaticResource TestConverter}}"  />
                            </ContextMenu>
                        </Setter.Value>
                    </Setter>

这些方法都有一个共同点,就是它们似乎都会导致我在命令中设置的断点,当网格加载时命中ONCE。进一步将TestConverter添加到引用并设置断点会导致它在加载时为网格中的每一行命中一次,但从未在单击命令时命中。

以下是ViewModel中命令的代码

public ICommand AcknowledgeViolationCommand
    {
        get
        {
            if (acknowledgeViolationCommand == null)  // BreakPoint is here
                acknowledgeViolationCommand = new RelayCommand(param => Test());


            return acknowledgeViolationCommand;
        }
    }

private void Test()
    {
        string a = "a"; //Breakpoint here
    }

对命令进行了更改,以防由于某种原因需要canExecute谓词。我确认了canExecute方法的断点确实触发了。

public ICommand AcknowledgeViolationCommand
    {
        get
        {
            if (acknowledgeViolationCommand == null) // BP here
                acknowledgeViolationCommand = new RelayCommand(param => Test(), param => YesDoIt());

            return acknowledgeViolationCommand;
        }
    }

private bool YesDoIt()
    {
        return true;  //BP here
    }

0 个答案:

没有答案