【发布时间】:2020-03-28 17:58:55
【问题描述】:
我想要完成的事情
我正在尝试让我的嵌套菜单项更改显示的用户控件。用更专业的术语来说,我试图:
- 获取附加到嵌套
MenuItem的点击事件(来自我的MyMenu.cs文件-实现INotifyPropertyChanged),以... - 使用
RoutedEventHandler(可能来自MyMenu.cs文件?- 实现UserControl),以... - 调用
SwitchScreen方法(来自我的MainWindow.cs文件-实现Window)
我卡住的地方
我似乎找不到将点击事件添加到相应菜单项的方法。
我当前的逻辑还要求将原始发件人作为参数传递,以便我可以识别要显示的正确MySubview。
XAML 处理程序
我尝试如下在 xaml 中添加点击事件,但它只将处理程序添加到第一个菜单项级别(而不是嵌套的菜单项元素)。
<MenuItem ItemsSource="{Binding Reports, Mode=OneWay}" Header="Reports">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<EventSetter Event="Click" Handler="MenuItem_Click"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
C# 设置器
我尝试添加一个 setter,在 this answer 中建议,但我似乎无法创建从 MyMenu.cs 到 MyMenuUserControl.cs 的点击事件。
Style style = new Style();
style.BasedOn = menuItem2.Style;
style.Setters.Add(new EventSetter( /* ??? */ ));
C# ICommand
我尝试过使用ICommand,在this answer 中提出建议,但我似乎无法创建从MyMenu.cs 到MyMenuUserControl.cs 的中继命令。
我可能在其中一次尝试中做错了什么,但我现在已经过了玩耍的地步,准备认输。
注意事项
实际结构
实际上,我的实际代码具有 n 嵌套 foreach 循环来生成菜单,如果 foreach 可枚举(例如 myObjects)只有一个元素,我将删除一层嵌套。
移除一层嵌套也会将点击事件上移一层。
我的最终菜单可能如下所示:
我的菜单项:
- 项目 (menuItem1)
- 项目 (menuItem2)
- 项目(menuItem3)+点击事件
- 项目(menuItem3)+点击事件
- 项目(menuItem2)+点击事件(见A)
- 项目 (menuItem2)
- 项目(menuItem1)+点击事件(见B)
A:只有一个 menuItem3 是嵌套的,因此我们将其移除(这是多余的)并将点击事件向上移动到 menuItem2。
B:menuItem2只有一个嵌套,menuItem3只有一个。两者都被删除,因为它们是多余的,我们将点击事件移动到 menuItem1。
这就是为什么我想在MyMenu 类中维护菜单项的创建。
其他建议
我可能会完全错误地处理这件事,我愿意接受改变我处理方式的建议。
代码
MyMenu.cs
此类中的构造函数生成我的菜单项及其子菜单项。
这是我尝试添加点击事件的地方。
class MyMenu : INotifyPropertyChanged
{
private List<MenuItem> menuItems = new List<MenuItem>();
public List<MenuItem> MenuItems
{
get { return menuItem; }
set
{
menuItem = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public List<Tuple<MyObject, MenuItem>> Map { get; private set; } = new List<Tuple<MyObject, MenuItem>>();
public MyMenu(List<MyObject> myObjects)
{
foreach(MyObject myObject in myObjects)
{
MenuItem menuItem1 = new MenuItem { Header = myObject.Name };
foreach(string s in myObject.Items)
{
MenuItem menuItem2 = new MenuItem { Header = s };
// Add click event to menuItem2 here
menuItem1.Items.Add(menuItem2);
Map.Add(new Tuple<MyObject, MenuItem>(myObject, menuItem2));
}
MenuItem.Add(menuItem1);
}
}
private void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
MyMenuUserControl.xaml
最小代码示例 UserControl(使用默认 xmlns 属性)。MyMenuUserControl.xaml.cs 仅具有带有 InitializeComponent(); 的构造函数
<UserControl>
<!-- xmlns default attributes in UserControl above removed for minimal code -->
<Menu>
<Menu.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</Menu.ItemsPanel>
<MenuItem ItemsSource="{Binding MenuItems, Mode=OneWay}" Header="My menu items"/>
</Menu>
</UserControl>
MyDataContext.cs
最小代码示例(PropertyChangedEventHandler 和 OnPropertyChanged() 代码与 MyMenu.cs 相同)。
构造函数只需设置Menu 和Subviews 属性。
类 MyDataContext : INotifyPropertyChanged { 私人 MyMenu 菜单; 公共 MyMenu 菜单 { 得到{返回菜单; } 放 { 菜单=价值; OnPropertyChanged(); } }
private List<MySubview> mySubviews;
public List<MySubview> MySubviews
{
get { return mySubviews; }
set
{
mySubviews = value;
OnPropertyChanged();
}
}
// ... rest of code removed to maintain minimal code
}
MainWindow.xaml.cs
Subview 包含MyObject 类型的属性。
这使我可以使用MyMenu 的Map 属性来确定为给定MenuItem 的点击显示哪个子视图。
是的,在MainWindow 地图上制作地图可能更容易,但是我在MyMenu 中的逻辑是一个最小示例(有关更多信息,请参阅Notes)。
公共部分类 MainWindow : Window { 公共主窗口() { 初始化组件();
// I get my data here
List<MyObject> myObjects = ...
List<MySubview> mySubviews = ...
DataContext = new MyDataContext(new MyMenu(myObjects), new MySubviews(mySubviews));
}
private void SwitchScreen(object sender, RoutedEventArgs e)
{
MyDataContext c = (MyDataContext)DataContext;
MyObject myObject = c.MyMenu.Map.Where(x => x.Item2.Equals(sender as MenuItem)).Select(x => x.Item1).First();
MySubview shownSubview = c.MySubviews.Where(x => x.MyObject.Equals(myObject)).First();
c.MySubviews.ForEach(x => x.Visibility = Visibility.Collapsed);
shownSubview.Visibility = Visibility.Visible;
}
}
【问题讨论】:
标签: c# wpf xaml event-handling