在代码中创建上下文菜单

4
我正在将三个相关但不同的DataGrid从xaml重构为代码,并遇到了更新上下文菜单标题文本的问题。
根据当前数据格单元格,命令和文本需要更新。标题文本在xaml中更新得很好,但是如下图所示,现在显示为空字符串。标题文本的setter触发属性更改,但我怀疑我的代码没有像xaml等效代码那样复制绑定。我也不确定Shared属性是否是我需要在代码中考虑的东西。
有人看到我如何改进我正在使用的代码吗?
问候, Berryl
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;
    }

更新

空字符串部分是我的疏忽 - 我没有初始化标题文本!下面的图片是我现在得到的,这是一个改进。但是文字应该更新为显示星期几,例如“让星期一成为完整的一天”。 enter image description here

Erno的编辑

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

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

enter image description here

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

最新更新

我试图按照这篇SO帖子的方法使我的绑定相对,但是没有成功。我的命令已经更新,也就是说它在正确的单元格上执行了,但是我无法让文本反映出它所在的单元格。最终,我决定像下面这样动态构建上下文菜单。它工作得很好,尽管我似乎应该能做得更好。

我会把答案给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;
    }
1个回答

1

我猜你想在代码中使用样式。

只需创建一个 Style 类的实例,设置其属性(包括绑定)并将其添加到树中的资源属性中。

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


@Erno。是的,有道理,但我可能做错了。请看我的最新编辑;你能帮我写一些代码吗?谢谢。 - Berryl
@Erno。我的错,我设置的是ContextMenu的样式而不是MenuItem的。现在看起来正常了,但仍然没有更新。 - Berryl
你的意思是运行时对样式的更改在菜单项中不可见吗?你不应该简单地引用样式(一种静态资源),而是使用menuItem.SetResourceReference(StyleProperty, "ContextMenuItemStyle"); - Emond
@Erno。不,它没有。我在一些代码后面对其进行了修改以使其工作。如果您有任何链接到应该工作的一些示例代码/绑定,我很想看看。此外,您认为哪个事件处理程序现在是处理ContextMenu的最佳位置?我将其放在DataGrid.CurrentCellChanged中,但我可以看到如果用户没有单击单元格,则无法将上下文菜单设置为空。 - Berryl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接