WPF MenuItem.Click 在父子关系后中断
我正在尝试使用各种菜单项(全部在代码中创建)动态填充菜单控件(位于 ControlTemplate 中),但我遇到了一些奇怪的问题。如果 MenuItems 全部创建为根项,则它们会成功触发 Click 事件。但是,一旦任何 MenuItem 成为另一个 MenuItem 的子项,父项和子项的 Click 事件都会停止触发。
XAML:
<ControlTemplate>
<Menu x:Name="MyMenu"/>
</ControlTemplate>
C#:
// This is in the control that the above ControlTemplate is created for
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
MenuItem L1 = new MenuItem() { Header = "L1" };
MyMenu.Items.Add(L1); // Add as root
L1.Click += new RoutedEventHandler(delegate { MessageBox.Show("L1 Click"); });
MenuItem L2 = new MenuItem() { Header = "L2" };
L1.Items.Add(L2); // Add as child of L1.
// Note: If this is a child of MyMenu, both MenuItems work as expected
L2.Click += new RoutedEventHandler(delegate { MessageBox.Show("L2 Click"); });
}
菜单显示正确,但子项上的任何单击事件都不会触发。如果我在 XAML 中预定义菜单并在 XAML 中设置所有 Click 事件,那么它可以完美运行 - 但它必须在代码中,因此这不是一个选项。另外,如果我将“L2”设为“MyMenu”的子项,即使其成为根项,L1 和 L2 会再次开始工作 - 但我也不能将所有内容都作为根项。 我有什么遗漏的吗?
谢谢你!
编辑 1:
我尝试了一个小实验,看看在将 L1 设为 L2 的父级并添加其 Click 事件之前,是否所有内容都已正确初始化。还是没有运气。这是我尝试过的:
XAML:
<ControlTemplate>
<Grid>
<Menu x:Name="MyMenu"/>
<Button x:Name="MyButton"/>
</Grid>
</ControlTemplate>
C#:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
MenuItem L1 = new MenuItem() { Header = "L1" };
MyMenu.Items.Add(L1);
MenuItem L2 = new MenuItem() { Header = "L2" };
MyMenu.Items.Add(L2); // Add this to the menu to make sure it gets initialised
// I created a button so I can make sure that the parenting
// and events are only added after the MenuItems are loaded
MyButton.Click += new RoutedEventHandler(MyButton_Clicked);
}
void MyButton_Clicked(object sender, RoutedEventArgs e)
{
// Note: If these two lines are removed, the events work fine
MyMenu.Items.Remove(L2);
L1.Items.Add(L2);
L1.Click += new RoutedEventHandler(delegate { MessageBox.Show("L1 Click"); });
L2.Click += new RoutedEventHandler(delegate { MessageBox.Show("L2 Click"); });
}
当窗口加载并显示所有内容时,我单击按钮,以便发生父子关系并添加事件。我看到 L2 被移动为 L1 的子级,但是当我单击其中一个时,它们不会响应 Click 事件。如果我阻止父子关系表单的发生,它们会响应 Click 事件。我很困惑为什么会发生这种情况!
编辑2:
我在一个干净的项目中复制了原始帖子中的所有内容,并且一切都很完美。因此,这不是 Menu 或 MenuItems 或它们的使用方式的问题。此问题的原因仍然未知...
编辑 3:
根据要求,我使用添加到窗口中的以下代码重新测试了此问题:
PreviewMouseLeftButtonDown += new MouseButtonEventHandler(delegate
{
// Use Ctrl key to enable MessageBox so focus is not lost when opening menu
if (Keyboard.Modifiers == ModifierKeys.Control)
MessageBox.Show("Window PreviewMouseLeftButtonDown");
});
当按住 ctrl 键单击“死”菜单项时,始终会触发 PreviewMouseLeftButtonDown。他们的 Click 事件在设置父级后继续停止工作。仍然没有解决方案,也没有表明问题...
编辑 4:
我做了以下测试,为 L1 和 L2 添加以下代码:
L1.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(delegate
{
MessageBox.Show("L1 PreviewMouseLeftButtonDown");
});
// Same for L2
单击时,MenuItem L1 和 L2 都响应 PreviewMouseLeftButtonDown,但在之后继续停止响应 Click被养育。
I am trying to dynamically populate a Menu control (which resides in a ControlTemplate) with various MenuItems (all created in code) but I am running into some weird problems. If the MenuItems are all created as root items, they fire their Click event successfully. But as soon as any MenuItem is made a child of another MenuItem, both the parent and child's Click events stop firing.
XAML:
<ControlTemplate>
<Menu x:Name="MyMenu"/>
</ControlTemplate>
C#:
// This is in the control that the above ControlTemplate is created for
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
MenuItem L1 = new MenuItem() { Header = "L1" };
MyMenu.Items.Add(L1); // Add as root
L1.Click += new RoutedEventHandler(delegate { MessageBox.Show("L1 Click"); });
MenuItem L2 = new MenuItem() { Header = "L2" };
L1.Items.Add(L2); // Add as child of L1.
// Note: If this is a child of MyMenu, both MenuItems work as expected
L2.Click += new RoutedEventHandler(delegate { MessageBox.Show("L2 Click"); });
}
The menu displays correctly, but none of the click events on the sub-items fire at all. If I pre-define the menu in XAML and set all Click events in XAML too, it works perfectly - but it has to be in code, so this is not an option. Also, if I make 'L2' to be a child of 'MyMenu', i.e. make it a root item instead, L1 and L2 start to work again - but I cannot have everything as root items either.
Is there something that I am missing?
Thank you!
EDIT 1:
I have tried a little experiment to see if everything was properly initialised before parenting L1 to L2 and adding their Click events. Still no luck. Here is what I tried:
XAML:
<ControlTemplate>
<Grid>
<Menu x:Name="MyMenu"/>
<Button x:Name="MyButton"/>
</Grid>
</ControlTemplate>
C#:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
MenuItem L1 = new MenuItem() { Header = "L1" };
MyMenu.Items.Add(L1);
MenuItem L2 = new MenuItem() { Header = "L2" };
MyMenu.Items.Add(L2); // Add this to the menu to make sure it gets initialised
// I created a button so I can make sure that the parenting
// and events are only added after the MenuItems are loaded
MyButton.Click += new RoutedEventHandler(MyButton_Clicked);
}
void MyButton_Clicked(object sender, RoutedEventArgs e)
{
// Note: If these two lines are removed, the events work fine
MyMenu.Items.Remove(L2);
L1.Items.Add(L2);
L1.Click += new RoutedEventHandler(delegate { MessageBox.Show("L1 Click"); });
L2.Click += new RoutedEventHandler(delegate { MessageBox.Show("L2 Click"); });
}
When the Window loads up and everything is displayed, I click on the Button so that the parenting happens and events are added. I see L2 being moved as a child of L1, but when I click either, they don't respond to Click events. If I prevent the parenting form happening, they do respond to Click events. I am so confused as to why this is happening!
EDIT 2:
I replicated everything from the original post in a clean project, and it all works perfectly. So it's not a problem with the Menu or MenuItems or the way they were used. The cause of this problem is still unknown...
EDIT 3:
As requested, I re-tested this with the following code added to the Window:
PreviewMouseLeftButtonDown += new MouseButtonEventHandler(delegate
{
// Use Ctrl key to enable MessageBox so focus is not lost when opening menu
if (Keyboard.Modifiers == ModifierKeys.Control)
MessageBox.Show("Window PreviewMouseLeftButtonDown");
});
PreviewMouseLeftButtonDown is always triggered when ctrl-clicking on the 'dead' MenuItems. Their Click events continue to stop working after being parented. Still no solution nor indication of the problem...
EDIT 4:
I did the following test, adding the below code for both L1 and L2:
L1.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(delegate
{
MessageBox.Show("L1 PreviewMouseLeftButtonDown");
});
// Same for L2
When Clicked, MenuItem L1 and L2 both respond to PreviewMouseLeftButtonDown, but continue to stop responding to Click after being parented.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我终于解开了这个谜团。在其中进行任何点击后,我追踪到父 Control 窃取焦点的问题,尽管奇怪的是菜单保持打开状态并对导航做出反应,即使它没有焦点。一切似乎都与 Focus() 的调用被删除有关。
所发生事件的详细信息:
没有 MenuItem 父子关系:
1) 我单击根 MenuItem,它响应 Click。
2) 然后 OnPreviewMouseDown 被父级拦截并调用 Focus() 。
由于 Click 已成功触发,因此在这种情况下不会出现因失去焦点而导致的不良结果。
WITH MenuItem 父子关系:
1) 我单击菜单,它会打开。
2) 然后 OnPreviewMouseDown 被父级拦截并调用 Focus() 。
3)菜单保持打开状态并继续对导航做出反应(这是注定要发生的吗??)。
4)当我第二次单击任何菜单项进行选择时,菜单最终意识到它失去了焦点并关闭 - 也放弃了单击。
然后,似乎就像单击了 MenuItem 并丢弃了...导致原始帖子中遇到的问题。
I've finally solved the mystery. I tracked down the problem to the parent Control stealing focus after any clicks are made within it, although it is weird that the menu stayed open and reacted to navigation even though it did not have focus. Everything seems to work with the call to Focus() being removed.
The details of what was happening:
WITHOUT MenuItem parenting:
1) I click on a root MenuItem and it responds to Click.
2) OnPreviewMouseDown is then intercepted by the parent and a call to Focus() is made.
There is no adverse results caused by the loss of focus in this situation since Click was successfully fired.
WITH MenuItem parenting:
1) I click on the menu and it opens.
2) OnPreviewMouseDown is then intercepted by the parent and a call to Focus() is made.
3) The menu stays open and continues to react to navigation (is this meant to happen??).
4) When I click the second time on any MenuItem to make a selection, the menu finally realises that it lost focus and closes - also discarding the click.
It then seems like a click was made and discarded by the MenuItem... leading to the problem experienced in the original post.
我正在为我的书“VB.Net Libraries-Part3”做一个项目。我需要做与您尝试的相同的事情。我遇到了同样的问题。但是我通过单击按钮创建运行时菜单项来规避这个问题。
我将 menu1 作为 menuStrip item.submenu1_1 到 submenu1_8 作为菜单项。minimenu1_11 到 minimenu1_18 作为子菜单项。我仅将 submenu1_1 放在非单击类别中。所有其他我插入到按钮单击事件中(全局声明是在main)。现在,如果您单击 submneu1_1,您将获得一个输出(我在主多行文本框编辑器中获得它)。单击按钮并在 menu1 的下拉菜单中获得带有子菜单的迷你菜单。相同的原理可以扩展到所有子菜单(使用单选按钮 - 激活每个子菜单下拉列表)。
相应的 .vbproj 文件是:-
**
**
来自 cmd 的编译调用是:-
msbuild.exe C:\Users\YourName\Desktop\Test\Test_Window.vbproj /t:ReBuild
C:\Users\YourName\Desktop\Test\bin\Debug\Test_Window.exe
测试:-单击 T.Menu 1st。您会看到“Hellow World!”在编辑器中。
现在单击 Dim1_1 按钮。您将看到完整的下拉迷你菜单。
问候
文卡特拉曼
I was doing a project for my book-'VB.Net Libraries-Part3'.I needed to do the same as what you attempted.I had the same problems.But i circumvented the problem by creating runtime menuitems by a button click.
I had menu1 as menuStrip item.submenu1_1 to submenu1_8 as menu items.minimenu1_11 to minimenu1_18 as submenu items.I put the submenu1_1 only in the non-click category.All others i inserted into a button click event(the global declarations were done in the main).Now if you click the submneu1_1 click you get one output(i got it in the main multiline textbox-Editor).Click the button and get the minimenus with submenus on dropdown of menu1.The same principle can be extended to all submenus(use RadioButtons-to activate each submenu dropdown).
The corresponding .vbproj file is:-
**
**
Compilation call from cmd is:-
msbuild.exe C:\Users\YourName\Desktop\Test\Test_Window.vbproj /t:ReBuild
C:\Users\YourName\Desktop\Test\bin\Debug\Test_Window.exe
Testing:-Click the T.Menu 1st.You get 'Hellow World!' in the Editor.
Now click the Dim1_1 button.You will see the full drop down minimenus.
regards
Venkatraman