WPF ContextMenu = {x:Null}但仍在ContentControl中显示菜单

时间:2014-10-15 14:35:48

标签: c# wpf contextmenu contentcontrol

我需要禁用TextBox的标准ContextMenu。我创建了一个新的WPF项目并添加了以下内容:

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
       <ContentControl>
           <ContentControl.ContentTemplate>
               <DataTemplate>
                    <TextBox ContextMenu="{x:Null}" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox>
                </DataTemplate>
           </ContentControl.ContentTemplate>
       </ContentControl>
    </Grid>
</Window>

但这就是我得到的:

enter image description here

以下代码可以正常使用:

<Grid>
     <TextBox ContextMenu="{x:Null}" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox>
</Grid>

为什么会这样?

更新

根据接受的答案,我创建了一个派生自TextBox的类,以便能够显示父母ContextMenu。

    public class TextBoxNoMenu: TextBox
    {
        public TextBoxNoMenu()
        {
            ContextMenu = null;
        }
    }

4 个答案:

答案 0 :(得分:3)

  

为什么会这样?

这是一个有趣的案例,控件的行为会根据属性的设置位置/方式而改变。

TextBox默认提供自己的上下文菜单。当您明确将ContextMenu本地值设置为null时,时间不会这样做。这就是您的简单示例中发生的情况TextBox直接位于Grid内。

但是,当您在模板中设置属性时,您实际上并未设置本地值;你正在设置一个&#34;父模板&#34;值。如果您使用DependencyPropertyHelper.GetValueSource()检查该值,则会看到基值来源为ParentTemplate而不是Local。因此,菜单仍然被覆盖。

有关不同类型的依赖项属性值源的详细信息,请参阅Dependency Property Value Precedence

@ OmegaMan建议分配一个隐藏的&#39;上下文菜单看起来效果很好。

答案 1 :(得分:1)

请注意,虽然您可能已禁用TextBox上的ContextMenu,但如果它在另一个控件中,您实际上可能会看到这样一个包装器的ContextMenu。试试Snooping它可以更具体地看到这种行为。

另请注意,WPF中的许多默认控制模板都可能通过添加自己的子对象而导致这些问题。看到default template for TextBox使用Border然后使用<ScrollViewer Margin="0" x:Name="PART_ContentHost" />,您很可能会看到TextBox的子对象的ContextMenu。

答案 2 :(得分:1)

这似乎是一个运行问题,其中X:Null没有“关闭”默认的上下文菜单。更好的方法是改变它的可见性:

<TextBox.ContextMenu>
    <ContextMenu Visibility="Collapsed"/>
</TextBox.ContextMenu>

答案 3 :(得分:0)

我遇到了类似的问题,但我是以编程方式生成控件,而我的父控件是dockpanel。根据接受的答案,我决定在后面的代码中设置null值。

        <Grid>
            <DockPanel>
               <TextBox Name="txtBox" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox>
            </DockPanel>
        </Grid>

然后

            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                txtBox.ContextMenu = null;
            }

编辑:我觉得这是一个随意的答案,因为它没有完全或直接解决这个问题。我做了一些挖掘,如果你实现了This Question答案中找到的方法,你可以在代码隐藏中找到文本框。

所以,如果你有这个

        <Grid>
           <ContentControl>
              <ContentControl.ContentTemplate>
                 <DataTemplate>
                    <TextBox Name="txtBox" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox>
                 </DataTemplate>
              </ContentControl.ContentTemplate>
           </ContentControl>
        </Grid>

然后您应该能够按名称找到您的文本框(在本例中为txtBox)并将上下文菜单设置为null

                TextBox myTextBox = FindChild<TextBox>(Application.Current.MainWindow, "txtBox");

                myTextBox.ContextMenu = null;

就我个人而言,我更喜欢用继承创建一个新类,但是对你有用。这仍然没有回答&#34;为什么会发生这种情况?&#34;但我认为接受的答案很好。