XAML名称范围和模板有关问题WPF的ContextMenu [英] Xaml Namescope and Template Question Concerning WPF ContextMenu

查看:182
本文介绍了XAML名称范围和模板有关问题WPF的ContextMenu的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的code一切正常,除了对文本菜单绑定。这显然​​是由于这样的事实,该文本菜单位于一个样式,这使它在不同的名称范围从XAML的其余部分的内侧。我要寻找一个解决方案,我不会在code-背后实例化一个文本菜单,因为在那里我有应用解决方案包含了很多绑定的一个非常大的ContextMenu应用。必须有在XAML做到这一点的一种方式,否则会看起来像一个严重的疏忽。另外请注意,我已经尝试过使用穿越和VisualTreeHelper的LogicalTreeHelper元素树,但我无法从窗口的根元素找到文本菜单(这些类显然跳过了有趣的元素)。总之,所有的code的如下。这可以粘贴到Visual Studio中一个新的WPF应用程序,并没有丢失。

Everything in the code below works except for the binding on the ContextMenu. This is evidently due to the fact that the ContextMenu is located inside of a Style, which puts it in a different namescope from the rest of the xaml. I am looking for a solution where I won't have to instantiate a ContextMenu in the code-behind, since the application where I have to apply the solution contains a very large ContextMenu with a lot of bindings. There must be a way to accomplish this in xaml, otherwise it would seem like a serious oversight. Also note that I've already tried traversing the element tree using VisualTreeHelper and LogicalTreeHelper, but I wasn't able to find the ContextMenu from the root element of the Window (these classes evidently skipped over the interesting elements). Anyway, all of the code is below. This can be pasted into a new WPF application in Visual Studio, and nothing is missing.

这里的code为App.xaml.cs(XAML中被保持不变):

Here's the code for App.xaml.cs (the xaml was left unchanged):

using System.Windows;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            WindowV windowV = new WindowV();
            WindowVM windowVM = new WindowVM();

            windowV.DataContext = windowVM;

            windowV.Show();
        }
    }
}

下面是什么最初的窗口1 XAML:

Here's the xaml for what was originally Window1:

<Window x:Class="WpfApplication1.WindowV"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:WpfApplication1"
        Name="MainWindow"
        Title="WindowV" Height="300" Width="300">
    <Window.Resources>
        <Style TargetType="{x:Type ItemsControl}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsLocked}" Value="true">
                    <Setter Property="ItemsSource" Value="{Binding LockedList}" />
                    <Setter Property="ItemTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <TextBlock Text="{Binding}" />
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsLocked}" Value="false">
                    <Setter Property="ItemsSource" Value="{Binding RegularList}" />
                    <Setter Property="ItemTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <TextBlock Text="{Binding}">
                                    <TextBlock.ContextMenu>
                                        <ContextMenu>
                                            <MenuItem Header="{Binding MenuItem1, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
                                            <MenuItem Header="{Binding MenuItem2, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
                                            <MenuItem Header="{Binding MenuItem3, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
                                        </ContextMenu>
                                    </TextBlock.ContextMenu>
                                </TextBlock>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="4*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ItemsControl Grid.Row="0" />
        <Button Name="ToggleButton"
                Grid.Row="1"
                Content="Toggle Lock"
                Click="OnToggleLock" />
    </Grid>
</Window>

下面是什么最初的窗口1 codebehind:

Here's the codebehind for what was originally Window1:

using System.Windows;
using System.Windows.Markup;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class WindowV : Window
    {
        public WindowV()
        {
            InitializeComponent();
        }

        private void OnToggleLock(object sender, RoutedEventArgs e)
        {
            if (((WindowVM)(DataContext)).IsLocked == true)
                ((WindowVM)(DataContext)).IsLocked = false;
            else
                ((WindowVM)(DataContext)).IsLocked = true;
        }
    }
}

一个新类添加到名为WindowVM项目。下面是它的code:

A new class was added to the project called WindowVM. Here's its code:

using System.Collections.Generic;
using System.ComponentModel;

namespace WpfApplication1
{
    public class WindowVM : INotifyPropertyChanged
    {
        public string MenuItem1
        {
            get
            {
                string str = "Menu item 1";
                return str;
            }
        }
        public string MenuItem2
        {
            get
            {
                string str = "Menu item 2";
                return str;
            }
        }
        public string MenuItem3
        {
            get
            {
                string str = "Menu item 3";
                return str;
            }
        }

        public List<string> LockedList
        {
            get
            {
                List<string> list = new List<string>();
                list.Add("This items control is currently locked.");
                return list;
            }
        }
        public List<string> RegularList
        {
            get
            {
                List<string> list = new List<string>();
                list.Add("Item number 1.");
                list.Add("Item number 2.");
                list.Add("Item number 3.");
                return list;
            }
        }

        private bool _isLocked;
        public bool IsLocked
        {
            get { return _isLocked; }
            set
            {
                if (_isLocked != value)
                {
                    _isLocked = value;
                    OnPropertyChanged("IsLocked");
                }
            }
        }

        public WindowVM()
        {
            IsLocked = false;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }
    }
}

任何有识之士将是非常美联社preciated。谢谢了!

Any insight would be very appreciated. Thanks much!

安德鲁

推荐答案

好吧,这个解决方案的工作原理:我改变了WindowV.xaml和WindowV.xaml.cs文件如下。以下更正修复XAML有关名称范围的问题。

Alright, this solution works: I changed the WindowV.xaml and WindowV.xaml.cs files as follows. The following corrections fix the problem concerning namescope in xaml.

下面是新WindowV.xaml文件:

Here's the new WindowV.xaml file:

<Window x:Class="WpfApplication1.WindowV"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:WpfApplication1"
        Name="RootElement"
        Title="WindowV" Height="300" Width="300">
    <Window.Resources>
        <ContextMenu x:Key="myContextMenu" DataContext="{Binding Path=DataContext, ElementName=RootElement}">
            <MenuItem Header="{Binding MenuItem1}" />
            <MenuItem Header="{Binding MenuItem2}" />
            <MenuItem Header="{Binding MenuItem3}" />
        </ContextMenu>
        <Style TargetType="{x:Type ItemsControl}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsLocked}" Value="true">
                    <Setter Property="ItemsSource" Value="{Binding LockedList}" />
                    <Setter Property="ItemTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <TextBlock Text="{Binding}" />
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsLocked}" Value="false">
                    <Setter Property="ItemsSource" Value="{Binding RegularList}" />
                    <Setter Property="ItemTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <TextBlock Text="{Binding}" ContextMenu="{StaticResource myContextMenu}" />
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="4*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ItemsControl Grid.Row="0" />
        <Button Name="ToggleButton"
                Grid.Row="1"
                Content="Toggle Lock"
                Click="OnToggleLock" />
    </Grid>
</Window>

下面是相应的code-背后:

Here's the corresponding code-behind:

using System.Windows;
using System.Windows.Markup;
using System;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class WindowV : Window
    {
        public WindowV()
        {
            InitializeComponent();

            System.Windows.Controls.ContextMenu contextMenu =
                FindResource("myContextMenu") as System.Windows.Controls.ContextMenu;

            NameScope.SetNameScope(contextMenu, NameScope.GetNameScope(this as DependencyObject));
            contextMenu.RegisterName("RootElement", this);
        }

        private void OnToggleLock(object sender, RoutedEventArgs e)
        {
            if (((WindowVM)(DataContext)).IsLocked == true)
                ((WindowVM)(DataContext)).IsLocked = false;
            else
                ((WindowVM)(DataContext)).IsLocked = true;
        }
    }
}

安德鲁

这篇关于XAML名称范围和模板有关问题WPF的ContextMenu的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆