Все в приведенном ниже коде работает, кроме привязки в ContextMenu. Это, очевидно, связано с тем, что ContextMenu находится внутри стиля, который помещает его в область имен, отличную от остальной части xaml. Я ищу решение, в котором мне не нужно будет создавать экземпляр ContextMenu в программном коде, поскольку приложение, в котором я должен применить решение, содержит очень большое ContextMenu с большим количеством привязок. Должен быть способ сделать это в xaml, иначе это может показаться серьезным упущением. Также обратите внимание, что я уже пробовал обходить дерево элементов, используя VisualTreeHelper и LogicalTreeHelper, но я не смог найти ContextMenu из корневого элемента Window (эти классы, очевидно, пропустили интересные элементы). Во всяком случае, весь код ниже. Это можно вставить в новое приложение WPF в Visual Studio, и ничего не пропало.
Вот код для 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();
}
}
}
Вот xaml для того, что изначально было 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>
Вот код для того, что изначально было 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));
}
}
}
Любое понимание будет очень оценено. Большое спасибо!
Andrew