WPF DataGrid ContextMenu命令绑定到MVVMLight RelayCommand <t>并不总是正常工作</t>

时间:2015-01-15 12:38:47

标签: wpf mvvm mvvm-light wpfdatagrid

我有一个WPF DataGrid,我希望使用MVVM添加ContextMenu。这个DataGrid位于UserControl(我删除了一堆我认为与问题的本质无关的内容):

<UserControl x:Class="Legend.MarkerMultiStatisticsControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:legend="clr-namespace:Legend"
             Name="Self"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <GroupBox Header="{Binding ElementName=Self, Path=StaisticsData.Title}">
        <DockPanel>
            <DataGrid 
                      DataContext="{Binding ElementName=Self}"
                      ItemsSource="{Binding ElementName=Self, Path=StaisticsData.Statistics}"
                      SelectionMode="Single"
                      CurrentCell="{Binding ElementName=Self, Path=CurrentCell, Mode=OneWayToSource}">
                <DataGrid.ContextMenu>
                    <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Mode=Self}, Path=PlacementTarget.DataContext}"
                                 ItemsSource="{Binding Path=Commands}">
                        <ContextMenu.ItemContainerStyle>
                            <Style TargetType="MenuItem">
                                <Setter Property="Header" Value="{Binding Header}"></Setter>
                                <Setter Property="Command" Value="{Binding Command, diag:PresentationTraceSources.TraceLevel=High}"></Setter>
                                <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.CurrentLegendCell}"></Setter>
                            </Style>
                        </ContextMenu.ItemContainerStyle>
                    </ContextMenu>
                </DataGrid.ContextMenu>
            </DataGrid>
        </DockPanel>
    </GroupBox>
</UserControl>

此控件有一个名为DependencyProperty的{​​{1}}我绑定菜单Command,其类型为ItemsSourceObservableCollection<LegendCommand>为< / p>

LegendCommand

这些命令在视图模型的不同位置生成。

在一个地方(public class LegendCommand : ObservableObject { private string _header; private ICommand _command; public string Header { get { return _header; } set { Set(()=>Header, ref _header, value); } } public ICommand Command { get { return _command; } set { Set(() => Command, ref _command, value); } } } 班级内Adapter与对照Commands绑定)我有以下内容:

Commands

在另一个地方(持有Commands.Add(new LegendCommand { Header = "From inside adapter...", Command = new RelayCommand<LegendCellInfo>(info => { MessageBox.Show(string.Format("State: {0}, Property: {1}", info.State, info.PropertyName)); }) }); 的视图模型)我有以下内容:

Adapter

我的问题是&#34;来自内部适配器......&#34;命令被执行但是&#34;选择&#34; ISN&#39;吨。我在&#34; Select&#34;中添加了一个断点。代码,但它从未被调用。

adapter.Commands.Add(new LegendCommand { Header = "Select", Command = new RelayCommand<LegendCellInfo>(info => { // selection logic }) }); &#39; ContextMenuItemsSource属性的绑定有效,因为我在菜单中看到了两个选项。 Commands的绑定可能有效,因为其中一个命令已执行。

我调试了代码和绑定,并提供以下信息:

ICommans集合包含两个元素,其哈希码为40262542和26818564(在Visual Studio的立即窗口中运行Commandsadapter.Commands[0].Command.GetHashCode()得到它们。)

当我右键单击adapter.Commands[1].Command.GetHashCode()

时,绑定跟踪会给出以下输出
DataGrid

如果我理解正确,我们可以看到发生了两个绑定操作 - 第一个绑定到System.Windows.Data Warning: 56 : Created BindingExpression (hash=11440639) for Binding (hash=54536677) System.Windows.Data Warning: 58 : Path: 'Command' System.Windows.Data Warning: 60 : BindingExpression (hash=11440639): Default mode resolved to OneWay System.Windows.Data Warning: 61 : BindingExpression (hash=11440639): Default update trigger resolved to PropertyChanged System.Windows.Data Warning: 62 : BindingExpression (hash=11440639): Attach to System.Windows.Controls.MenuItem.Command (hash=54276594) System.Windows.Data Warning: 67 : BindingExpression (hash=11440639): Resolving source System.Windows.Data Warning: 70 : BindingExpression (hash=11440639): Found data context element: MenuItem (hash=54276594) (OK) System.Windows.Data Warning: 78 : BindingExpression (hash=11440639): Activate with root item LegendCommand (hash=5940773) System.Windows.Data Warning: 108 : BindingExpression (hash=11440639): At level 0 - for LegendCommand.Command found accessor RuntimePropertyInfo(Command) System.Windows.Data Warning: 104 : BindingExpression (hash=11440639): Replace item at level 0 with LegendCommand (hash=5940773), using accessor RuntimePropertyInfo(Command) System.Windows.Data Warning: 101 : BindingExpression (hash=11440639): GetValue at level 0 from LegendCommand (hash=5940773) using RuntimePropertyInfo(Command): RelayCommand`1 (hash=40262542) System.Windows.Data Warning: 80 : BindingExpression (hash=11440639): TransferValue - got raw value RelayCommand`1 (hash=40262542) System.Windows.Data Warning: 89 : BindingExpression (hash=11440639): TransferValue - using final value RelayCommand`1 (hash=40262542) System.Windows.Data Warning: 56 : Created BindingExpression (hash=31617173) for Binding (hash=54536677) System.Windows.Data Warning: 58 : Path: 'Command' System.Windows.Data Warning: 60 : BindingExpression (hash=31617173): Default mode resolved to OneWay System.Windows.Data Warning: 61 : BindingExpression (hash=31617173): Default update trigger resolved to PropertyChanged System.Windows.Data Warning: 62 : BindingExpression (hash=31617173): Attach to System.Windows.Controls.MenuItem.Command (hash=16119107) System.Windows.Data Warning: 67 : BindingExpression (hash=31617173): Resolving source System.Windows.Data Warning: 70 : BindingExpression (hash=31617173): Found data context element: MenuItem (hash=16119107) (OK) System.Windows.Data Warning: 78 : BindingExpression (hash=31617173): Activate with root item LegendCommand (hash=16131920) System.Windows.Data Warning: 107 : BindingExpression (hash=31617173): At level 0 using cached accessor for LegendCommand.Command: RuntimePropertyInfo(Command) System.Windows.Data Warning: 104 : BindingExpression (hash=31617173): Replace item at level 0 with LegendCommand (hash=16131920), using accessor RuntimePropertyInfo(Command) System.Windows.Data Warning: 101 : BindingExpression (hash=31617173): GetValue at level 0 from LegendCommand (hash=16131920) using RuntimePropertyInfo(Command): RelayCommand`1 (hash=26818564) System.Windows.Data Warning: 80 : BindingExpression (hash=31617173): TransferValue - got raw value RelayCommand`1 (hash=26818564) System.Windows.Data Warning: 89 : BindingExpression (hash=31617173): TransferValue - using final value RelayCommand`1 (hash=26818564) ,第二个绑定到'RelayCommand'1 (hash=40262542) - 顺便说一句,这些是我的两个命令的哈希码。

此外,不会发生例外或其他错误。

我陷入了调查之中。还有什么地方可以看?

更新1 : 当我更改&#34中的代码时;选择&#34;命令以下代替我之前的代码:

'RelayCommand'1 (hash=26818564)

然后代码突然开始工作......

更新2 : 原始命令使用adapter.Commands.Add(new LegendCommand { Header = "Select", Command = new RelayCommand<LegendCellInfo>(info => { MessageBox.Show("yes"); }) }); 类的成员。在线搜索MVVMLight Adapter和成员函数的问题,发现了这个问题:RelayCommand with Argument throwing MethodAccessException (但显然我想继续使用MVVMLight ......)

更新3 :读取RelayCommand的MVVMLight代码并且它不会保存对方法的硬引用,所以我认为没有什么能保持lambda活着。现在将重构代码并在此处更新(如果有效)。

1 个答案:

答案 0 :(得分:7)

实际上,原因是MVVMLight的弱引用并未使“选择”命令保持活跃状态​​。 我在这里更详细地写了这篇文章:http://blogs.microsoft.co.il/dinazil/2015/01/16/relaycommands-weakfuncs/