【问题标题】:context menu creation in code在代码中创建上下文菜单
【发布时间】:2011-04-03 23:50:46
【问题描述】:

我正在将 xaml 中的三个相关但不同的 DataGrid 重构为代码,并遇到更新上下文菜单标题文本的问题。

命令和文本需要根据哪个数据网格单元格是当前单元格进行更新。标题文本在 xaml 中更新得很好,但从下图中可以看出,它现在显示为一个空字符串。该命令本身可以正常工作,并且可以在正确的网格单元上工作。

标题文本触发属性的设置器已更改,但我怀疑我的代码没有像 xaml 等效项那样复制绑定。我也不确定 Shared 属性是否是我需要在代码中考虑的内容。

有人知道我可以如何改进我正在使用的代码吗?

干杯,
浆果

XAML 样式建立绑定

<ContextMenu x:Key="NonProjectActivityContextMenu" x:Shared="true">

    <MenuItem 
        DataContext="{Binding MakeEachWeekDayFullDayCommand}" Command="{Binding .}" 
        Header="{Binding HeaderText}" InputGestureText="{Binding InputGestureText}"      
        />
    <MenuItem 
        DataContext="{Binding MakeFullDayCommand}" Command="{Binding .}" 
        Header="{Binding HeaderText}" InputGestureText="{Binding InputGestureText}"      
        />
</ContextMenu>

<!-- Bindings assumes a VmMenuItem (Command Reference) -->
<Style x:Key="ContextMenuItemStyle" TargetType="{x:Type MenuItem}">
    <Setter Property="Header" Value="{Binding HeaderText}"/>
    <Setter Property="InputGestureText" Value="{Binding InputGestureText}" />
    <Setter Property="Command" Value="{Binding Command}" />
    <Setter Property="Icon" Value="{Binding Icon}" />
    <Setter Property="Tag" Value="{Binding IdTag}" />
    <Setter Property="ItemsSource" Value="{Binding Children}"/>
</Style>

代码

    protected virtual ContextMenu _GetContextMenu() {
        var menuItems = _dataContext.MenuItems.Select(menuItem => menuItem.ToMenuItem());
        var cm = new ContextMenu();
        foreach (var item in menuItems) {
            cm.Items.Add(item);
        }
        return cm;
    }

更新

好吧,空字符串部分只是我自己的愚蠢 - 我没有初始化标题文本!下图是我现在得到的,算是改进了。文本应更新为星期几,即“使星期一成为一整天”

为 Erno 编辑

我正在为网格本身设置列和样式,如下所示,所以我认为我可以获取上下文菜单的资源并进行设置。

然而,正如您从图片中看到的那样,我得到了一个奇怪的结果 - 就像上下文菜单覆盖了整个网格!

    private void OnDataGridLoaded(object sender, RoutedEventArgs e)
    {
        _dataContext = (ActivityCollectionViewModel)DataContext;

        IsSynchronizedWithCurrentItem = true;
        Style = (Style)FindResource(GRID_STYLE_NAME);

        _AddColumns();

        var timeSheetColumns = Columns.Cast<TimesheetGridColumn>();
        foreach (var col in timeSheetColumns)
        {
            col.SetHeader();
            col.SetCellStyle(this);
            col.SetBinding();
        }

        if(DesignerProperties.GetIsInDesignMode(this)) {
            // just so the designer doesn't hit a null reference on the data context
            ItemsSource = new ObservableCollection<ActivityViewModel>();
        }
        else {
            // ok, we have a runtime data context to work with
            ItemsSource = _dataContext.ActivityVms;
            InputBindings.AddRange(_GetKeyBindings());
            ContextMenu = _GetContextMenu();
            ContextMenu.Style = (Style)FindResource("ContextMenuItemStyle");
        }
    }


    private void OnDataGridLoaded(object sender, RoutedEventArgs e)
    {
        _dataContext = (ActivityCollectionViewModel)DataContext;

        IsSynchronizedWithCurrentItem = true;
        Style = (Style)FindResource(GRID_STYLE_NAME);

        _AddColumns();

        var timeSheetColumns = Columns.Cast<TimesheetGridColumn>();
        foreach (var col in timeSheetColumns)
        {
            col.SetHeader();
            col.SetCellStyle(this);
            col.SetBinding();
        }

        if(DesignerProperties.GetIsInDesignMode(this)) {
            // just so the designer doesn't hit a null reference on the data context
            ItemsSource = new ObservableCollection<ActivityViewModel>();
        }
        else {
            // ok, we have a runtime data context to work with
            ItemsSource = _dataContext.ActivityVms;
            InputBindings.AddRange(_GetKeyBindings());
            ContextMenu = _GetContextMenu();
            ContextMenu.Style = (Style)FindResource("ContextMenuItemStyle");
        }
    }

最新更新

我尝试根据this SO post 使我的绑定相对,但没有骰子。我的命令已更新,这意味着它在正确的单元格上执行,但我无法让文本反映它是哪个单元格。我终于决定动态构建上下文菜单,如下所示。它工作得很好,虽然看起来我应该能够做得更好。

我将把答案交给 Erno 并结束。

    private void OnCurrentCellChanged(object sender, EventArgs e)
    {
        if (ReferenceEquals(null, sender)) return;
        var grid = (DataGrid)sender;
        var selectedActivity = (ActivityViewModel)grid.CurrentItem;
        if (ReferenceEquals(selectedActivity, null)) return;

        if (_isEditableDayOfTheWeekColumn(grid.CurrentColumn))
        {
            var dowCol = (DayOfTheWeekColumn)grid.CurrentColumn;
            var index = Convert.ToInt32(dowCol.DowIndex);
            selectedActivity.SetSelectedAllocationVm(index);
        }
        else
        {
            selectedActivity.SetSelectedAllocationVm(-1);
        }
        var commands = selectedActivity
            .AllCommands
            .Select(vmMenuItem => vmMenuItem.Command.ToMenuItem());
        var cm = new ContextMenu();
        foreach (var item in commands)
        {
            //item.SetResourceReference(StyleProperty, "ContextMenuItemStyle");
            cm.Items.Add(item);
        }
        grid.ContextMenu = cm;
    }

【问题讨论】:

    标签: wpf silverlight contextmenu headereditemscontrol


    【解决方案1】:

    我猜你也想在代码中使用样式。 只需创建 Style 类的实例,设置其属性(包括绑定)并将其添加到树中的 Resources 属性。

    接下来,使用生成的菜单项中的样式。

    【讨论】:

    • @Erno。是的,有道理,但我一定做得不对。请参阅我的最新编辑;你也可以划出一些代码吗?干杯
    • @Erno。我的错,我在 ContextMenu 而不是 MenuItem 上设置样式。它看起来又正常了,但仍然没有更新
    • 您的意思是在菜单项中看不到样式的运行时更改吗?您不应该简单地引用样式(一种静态资源),而是使用 menuItem.SetResourceReference(StyleProperty, "ContextMenuItemStyle");
    • @Erno。不,它没有。我在后面的一些代码中破解了它以使其工作。如果您有任何指向应该工作的示例代码/绑定的链接,我很乐意看到它。另外,您认为目前处理 ContextMenu 的最佳位置是哪个事件处理程序?我在 DataGrid.CurrentCellChanged 中有它,但如果用户没有单击单元格,我可以看到在哪里取消上下文菜单。
    猜你喜欢
    • 2016-08-19
    • 1970-01-01
    • 2014-07-27
    • 1970-01-01
    • 2017-05-13
    • 2022-01-03
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多