除了ContextMenu上的绑定之外,下面代码中的所有内容都有效。这显然是由于ContextMenu位于Style内部,它将其置于与xaml其余部分不同的名称范围内。我正在寻找一个解决方案,我不必在代码隐藏中实例化ContextMenu,因为我必须应用解决方案的应用程序包含一个非常大的ContextMenu,其中包含大量绑定。必须有一种方法可以在xaml中实现这一点,否则它看起来像是一个严重的疏忽。另请注意,我已经尝试使用VisualTreeHelper和LogicalTreeHelper遍历元素树,但是我无法从Window的根元素中找到ContextMenu(这些类明显地跳过了有趣的元素)。无论如何,所有代码都在下面。这可以粘贴到Visual Studio中的新WPF应用程序中,并且不会遗漏任何内容。
这是App.xaml.cs的代码(xaml保持不变):
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();
}
}
}
这是原来Window1的xaml:
<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>
这是最初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的项目中添加了一个新类。这是它的代码:
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));
}
}
}
任何见解都将非常感激。非常感谢!
安德鲁
答案 0 :(得分:0)
好的 - 我在完成你想要完成的工作时遇到了一些麻烦 - 但请尝试以下方法:
<ContextMenu>
<MenuItem Header="{Binding DataContext.MenuItem1, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
...
为了使您的代码更容易,您可以尝试:
<ContextMenu DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<MenuItem Header="{Binding MenuItem1}"/>
...
问题在于您绑定了UI元素Window,该窗口没有名为MenuItem1等的属性.DataContext属性包含您感兴趣的数据。
答案 1 :(得分:0)
好的,这个解决方案有效:我更改了WindowV.xaml和WindowV.xaml.cs文件,如下所示。以下更正修复了xaml中关于名称范围的问题。
这是新的WindowV.xaml文件:
<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>
这是相应的代码隐藏:
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;
}
}
}
安德鲁