从 ListView 的 ItemContainer 为 ContextMenu 设置 DataContext?

Posted

技术标签:

【中文标题】从 ListView 的 ItemContainer 为 ContextMenu 设置 DataContext?【英文标题】:Setting the DataContext for a ContextMenu from a ListView's ItemContainer? 【发布时间】:2011-07-29 13:23:15 【问题描述】:

我正在使用 mvvm 模式,我很难从 ListView 的 ItemContainerStyle 中弄清楚如何在 ContextMenu 上设置 DataContext。

我也不明白为什么 ListView.ContextMenu 和 ListView 的 GridView.ColumnHeaderContextMenu 可以从我的视图模型中看到属性和命令,而 ListView.ItemContainerStyle 中的 ContextMenu 却不能。

错误

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“货币”(HashCode=43406546)上找不到“AddMenuItem”属性。绑定表达式:路径=添加菜单项; DataItem='货币' (HashCode=43406546);目标元素是'ContextMenu'(名称='');目标属性是“ItemsSource”(类型“IEnumerable”)

查看

<!-- Removed styles for clarity. -->
<UserControl>

<!-- Add ElementSpy to the UserControl’s rsources -->
<UserControl.Resources>
    <framework:ElementSpy x:Key="spy" />
</UserControl.Resources>

<ListView ItemsSource="Binding Currency">

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <!-- 'AddMenuItem' property not found on 'object' 'Currency' -->
                    <!-- ContextMenu ItemsSource="Binding AddMenuItem" / -->

                    <!-- Use the ElementSpy resource -->
                    <ContextMenu ItemsSource="Binding Source=StaticResource spy, Path=Element.DataContext.AddMenuItem" />
                </Setter.Value>
            </Setter>
        </Style>
    </ListView.ItemContainerStyle>

    <ListView.ContextMenu>
        <!-- Works -->
        <ContextMenu ItemsSource="Binding EditMenuItem" />
    </ListView.ContextMenu>

    <ListView.View>
        <GridView>
            <GridView.ColumnHeaderContextMenu>
                <!-- Works -->
                <ContextMenu ItemsSource="Binding SortMenuItem" />
            </GridView.ColumnHeaderContextMenu>

            <GridViewColumn Header="Code"
                            DisplayMemberBinding="Binding Path=Code" />

            <GridViewColumn Header="Description"
                            DisplayMemberBinding="Binding Path=Description" />

            <GridViewColumn Header="Exchange Rate"
                            DisplayMemberBinding="Binding Path=ExchangeRate" />
        </GridView>

    </ListView.View>

</ListView>
</UserControl>

代码背后

[Export(ViewNames.CurrencyMasterView, typeof(IMasterView))]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class CurrencyMasterView
    : UserControl, IMasterView

    public CurrencyMasterView()
    
        InitializeComponent();
    

    [Import]
    private MasterViewModel ViewModel
    
        set
        
            this.DataContext = value;
        
    

视图模型

[Export(typeof(MasterViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class MasterViewModel
    : ViewModelBase

    [ImportingConstructor]
    public MasterViewModel(IGeneralController generalController, IRegionManager regionManager)
    
    

    public ObservableCollection<Currency> Currency
    
        get
        
            return this.currency;
        

        set
        
            if (this.currency != value)
            
                this.currency = value;
                this.RaisePropertyChanged(() => this.Currency);
            
        
    

    public List<MenuItemMvvm> SortMenuItem
    
        get
        
            return this.CreateSortMenuItem();
        
    

    public List<MenuItemMvvm> EditMenuItem
    
        get
        
            return this.CreateEditMenuItem();
        
    

    public List<MenuItemMvvm> AddMenuItem
    
        get
        
            return this.CreateAddMenuItem();
        
    

    private List<MenuItemMvvm> CreateEditMenuItem()
    
        var menu = new List<MenuItemMvvm>();

        menu.Add(new MenuItemMvvm("_Edit")
        
            Command = this.EditCommand,
            Icon = new Image
            
                Source = new BitmapImage(new Uri("pack://application:,,,/POS.Modules.Core;component/Resources/Images/16X16/Edit.png"))
            
        );

        menu.Add(new MenuItemMvvm("_Duplicate")
        
            Command = this.DuplicateCommand,
            Icon = new Image
            
                Source = new BitmapImage(new Uri("pack://application:,,,/POS.Modules.Core;component/Resources/Images/16X16/Copy.png"))
            
        );

        menu.Add(new MenuItemMvvm("_Delete")
        
            Command = this.DeleteCommand,
            Icon = new Image
            
                Source = new BitmapImage(new Uri("pack://application:,,,/POS.Modules.Core;component/Resources/Images/16X16/Delete.png"))
            
        );


        return menu;
    

    // Other methods removed for clarity

【问题讨论】:

kevin:见 ***.com/questions/504533 和 ***.com/questions/2306386 - 您可以通过 ContextMenu.PlacementTarget 进行绑定。 【参考方案1】:

这个问题帮助我弄清楚了。 WPF MenuItem.Command binding to ElementName results to System.Windows.Data Error: 4 : Cannot find source for binding with reference

我为其他遇到此问题的人更新了源代码。

为了快速参考,这就是我所做的。

添加 Josh Smith 的 ElementSpy 类。 Enable ElementName Bindings with ElementSpy

将 ElementSpy 添加到 UserControl 的 rsources。

<UserControl.Resources>
    <framework:ElementSpy x:Key="spy" />
</UserControl.Resources>

然后绑定到资源并使用 Element 属性绑定到 DataContext 和您选择的属性。

<ContextMenu ItemsSource="Binding Source=StaticResource spy, Path=Element.DataContext.AddMenuItem" />

【讨论】:

【参考方案2】:

您必须在绑定中使用 RelativeSource 和 PlacementTarget。我使用以下 xaml 添加上下文菜单来设置数据网格列的可见性。

  <DataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Spalten ein-/ausblenden">                           
                        <StackPanel>
                            <ItemsControl 
                            ItemsSource="Binding RelativeSource=RelativeSource AncestorType=ContextMenu, Path=PlacementTarget.Columns, Mode=OneWay"
                            ItemTemplate="StaticResource Visibility4DataGridColumns"
                            ></ItemsControl>
                        </StackPanel>
                    </MenuItem>
                </ContextMenu>
            </DataGrid.ContextMenu>

【讨论】:

以上是关于从 ListView 的 ItemContainer 为 ContextMenu 设置 DataContext?的主要内容,如果未能解决你的问题,请参考以下文章

从 Firebase 向 ListView 添加条目

android从broadcastreceiver刷新listview

从 URL 加载带有 JSON 数据的 ListView

我需要从后台线程访问listview的适配器

如何从 C++ 设置 ListView 模型?

从 ListView 更改特定元素