我有一个带有ViewModel的窗口作为DataContext。我的窗口包含一个ItemsControl,它的ItemsSource绑定到一个viewmodel对象集合。
“我的ItemsControl”将Canvas用于ItemsPanelTemplate。 DataTemplate包括一个带有关联的ContextMenu的Ellipse。那个ContextMenu只有一个MenuItem。
“我的窗口”视图模型包含一个ICommand,该ICommand带有一个对象参数(当前的ItemsSource项)。
我试图右键单击ItemsControl中的一个椭圆并打开ContextMenu,然后单击MenuItem以执行ICommand并将当前的ItemsSource项作为参数传递。
由于某种原因,我无法从ContextMenu中访问Window的DataContext。我已经尝试研究此问题,但是所提出的解决方案似乎都不适合我。
我试图通过使用Window的元素名称并找到祖先类型来访问Windows数据上下文,但是没有运气。
public class VM_MainWindow : ViewModelBase
{
public DelegateCommand<EllipseObject> TestClick { get; }
// constructor
public VM_MainWindow()
{
// initialization
EllipseCollection = DynamicData.Ellipses;
ScreenResolutionWidth = ClientConfig.Info.ScreenResolutionWidth - 8;
ScreenResolutionHeight = ClientConfig.Info.ScreenResolutionHeight - 120;
// commands
TestClick = new DelegateCommand<EllipseObject>(OnTestClickCommand);
}
#region "Properties"
private ObservableCollection<EllipseObject> _ellipseCollection;
public ObservableCollection<EllipseObject> EllipseCollection
{
get => _ellipseCollection;
set
{
_ellipseCollection = value;
OnPropertyChanged("EllipseCollection");
}
}
private int _screenResolutionWidth;
public int ScreenResolutionWidth
{
get => _screenResolutionWidth;
set
{
_screenResolutionWidth = value;
OnPropertyChanged("ScreenResolutionWidth");
}
}
private int _screenResolutionHeight;
public int ScreenResolutionHeight
{
get => _screenResolutionHeight;
set
{
_screenResolutionHeight = value;
OnPropertyChanged("ScreenResolutionHeight");
}
}
#endregion
private void OnTestClickCommand(EllipseObject eObj)
{
MessageBox.Show("Ellipse Name: " + eObj.DisplayName, "Test", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
public class DelegateCommand<T> : System.Windows.Input.ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public DelegateCommand(Action<T> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
return true;
return _canExecute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public void Execute(object parameter)
{
_execute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
这是MainWindow.xaml,请注意,我的窗口名为x:Name =“ mainWindow”:
<Window.DataContext>
<viewModels:VM_MainWindow/>
</Window.DataContext>
<Grid Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="27px"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="30px"/>
</Grid.RowDefinitions>
<Grid x:Name="icContainerGrid" Grid.Row="1" Background="{Binding TrackMapBackground}">
<Grid>
<!-- ELLIPSES -->
<ItemsControl ItemsSource="{Binding EllipseCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" Width="{Binding ScreenResolutionWidth}" Height="{Binding ScreenResolutionHeight}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X1}"/>
<Setter Property="Canvas.Top" Value="{Binding Y1}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="24" Height="24" Fill="Red">
<Ellipse.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu item 1" Command="{Binding ElementName=mainWindow, Path=DataContext.TestClick}" CommandParameter="{Binding}"/>
</ContextMenu>
</Ellipse.ContextMenu>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
</Grid>
我希望我的命令在单击MenuItem时触发,但是不会。
运行该应用程序时,我收到以下绑定错误:
System.Windows.Data错误:4:找不到参考'ElementName = mainWindow'的绑定源。 BindingExpression:Path = DataContext.TestClick; DataItem = null;目标元素是'MenuItem'(Name ='');目标属性为“命令”(类型为“ ICommand”)
答案 0 :(得分:0)
问题已解决:
经过大量阅读,我终于设法找到一种解决方案,该解决方案涉及使用模板对象的标签存储数据上下文,然后可以通过ContextMenu的MenuItem通过ContextMenu的PlacementTarget属性对其进行访问:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="{Binding Width}" Height="{Binding Height}" Fill="{Binding DisplayColor}" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext}">
<Ellipse.ContextMenu>
<ContextMenu>
<MenuItem Header="Menu item 2" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.TestClick}" CommandParameter="{Binding}"/>
</ContextMenu>
</Ellipse.ContextMenu>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
由于某种原因,我完全无法从ContextMenu内访问Window的数据上下文。此修复程序可能并不理想,但对我有用。
希望这可以帮助遇到类似问题的其他人。
答案 1 :(得分:-1)
如果要访问DataTemplate中的DataContext,请尝试以下操作:
{Binding DataContext.YourProperty, RelativeSource={RelativeSource AncestorType={x:Type Window}}}