【发布时间】:2019-04-13 05:29:22
【问题描述】:
我有一个带有 viewmodel 作为 DataContext 的窗口。我的窗口包含一个 ItemsControl,它的 ItemsSource 绑定到一个 viewmodel 对象集合。
我的 ItemsControl 使用画布作为 ItemsPanelTemplate。 DataTemplate 包含一个 Ellipse 和一个与之关联的 ContextMenu; ContextMenu 有一个 MenuItem。
我的窗口视图模型包含一个 ICommand,它接受一个对象参数(当前 ItemsSource 项)。
我正在尝试右键单击我的 ItemsControl 中的一个省略号并调出 ContextMenu,然后单击 MenuItem 以执行 ICommand 并将当前 ItemsSource 项作为参数传递。
由于某种原因,我无法从 ContextMenu 中访问 Window 的 DataContext。我已尝试研究此问题,但建议的解决方案似乎都不适合我。
我尝试通过使用 Window 的元素名和查找祖先类型来访问 Window 数据上下文,但是没有运气。
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;数据项=空;目标元素是'MenuItem'(名称='');目标属性是“命令”(输入“ICommand”)
【问题讨论】:
-
尝试使用相对源绑定而不是元素名称来查找窗口,例如
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}您的错误也说明了 mainGrid 而不是 mainWindow -
Pavel,我所做的错误是正确的,我只是忘记更新我的帖子以反映以前的更改。我尝试了您使用相对来源的建议,但仍然没有运气