将命令绑定到位于 ListView 内的上下文菜单内的 viewModel
我正在尝试将上下文菜单项绑定到我在 ViewModel 中定义的命令。上下文菜单位于 ListView 内部,我也将其绑定到 CollectionViewSource,我认为这就是问题的原因。
我已成功将 listView 集合中的所选项目绑定到我的 ViewModel,但是当我尝试使用相同的方式将上下文菜单项命令绑定到我的 ViewModel 时,它不起作用。我希望任何人都有时间阅读下面的所有代码,并让我了解我做错了什么。
诗。我不得不更改一些名称,以免泄露该应用程序的内容。
在我的 ViewModel 中,我定义了以下内容:
public ObservableCollection<ListItemViewModel> ListViewItemViewModels {get; set;}
public MyListItem SelectedListItemViewModel {get; set;}
private RelayCommand _runCommand;
public ICommand RunCommand {
get {
return _runCommand ??
( _runCommand = new RelayCommand( param => RunReport(), param => CanRunReport ) );
}
}
private void RunReport() {
Logger.Debug("Run report");
}
然后在我的 View 中,我设置了一个 ListView,如下所示:
<ListView DataContext="{StaticResource ListGroups}"
ItemsSource="{Binding}"
ItemContainerStyle="{StaticResource ListItemStyle}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }, Path=DataContext.SelectedListItem, UpdateSourceTrigger=PropertyChanged}"
Margin="10,10,0,10">
<ListView.GroupStyle>
<StaticResourceExtension ResourceKey="AccountGroupStyle"/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Path=DisplayTitle}"/>
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Path=DateString}"/>
</GridView>
</ListView.View>
<ListView.ContextMenu>
<ContextMenu Name="ListViewContextMenu">
<MenuItem Header="Run" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }, Path=DataContext.RunCommand}"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
CollectionViewSource 定义如下:
<DataTemplate x:Key="ListViewListTemplate" DataType="{x:Type ViewModels:ListItemViewModel}">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=DisplayTitle}" Margin="8,0,0,0"/>
</StackPanel>
</DataTemplate>
<CollectionViewSource Source="{Binding Path=ListItemViewModels}" x:Key="ListItemGroups">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="ListItemGroupName"/>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<ComponentModel:SortDescription PropertyName="Index" Direction="Ascending"/>
<ComponentModel:SortDescription PropertyName="DisplayTitle" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<GroupStyle x:Key="ListItemGroupStyle">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<!-- The text binding here is refered to the property name set above in the propertyGroupDescrition -->
<TextBlock x:Name="text" Background="{StaticResource DateGroup_Background}" FontWeight="Bold" Text="{Binding Path=Name}"
Foreground="White"
Margin="1"
Padding="4,2,0,2"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<Style x:Key="ListItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a ReconciliationTaskViewModel object.
-->
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ItemsControl.AlternationIndex" Value="1" />
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#EEEEEEEE" />
</MultiTrigger>
</Style.Triggers>
</Style>
I am trying to bind a context menu item to a command that I have defined in my ViewModel. The context menu sits inside a ListView that I also have bound to a CollectionViewSource, and this I think is the cause of the problem.
I have managed to bind the selected item in the listView collection to my ViewModel, but when I am trying to use the same way to bind the context menu item command to my ViewModel it doesn't work. I hope that anybody have the time to read through all the code below and give me some idea about what I am doing wrong.
Ps. I have had to change some of the names in order to not give away what the application is about.
In my ViewModel I have defined the followning:
public ObservableCollection<ListItemViewModel> ListViewItemViewModels {get; set;}
public MyListItem SelectedListItemViewModel {get; set;}
private RelayCommand _runCommand;
public ICommand RunCommand {
get {
return _runCommand ??
( _runCommand = new RelayCommand( param => RunReport(), param => CanRunReport ) );
}
}
private void RunReport() {
Logger.Debug("Run report");
}
Then in my View I have set upp a ListView as follows:
<ListView DataContext="{StaticResource ListGroups}"
ItemsSource="{Binding}"
ItemContainerStyle="{StaticResource ListItemStyle}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }, Path=DataContext.SelectedListItem, UpdateSourceTrigger=PropertyChanged}"
Margin="10,10,0,10">
<ListView.GroupStyle>
<StaticResourceExtension ResourceKey="AccountGroupStyle"/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Path=DisplayTitle}"/>
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Path=DateString}"/>
</GridView>
</ListView.View>
<ListView.ContextMenu>
<ContextMenu Name="ListViewContextMenu">
<MenuItem Header="Run" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid},AncestorLevel=1 }, Path=DataContext.RunCommand}"/>
</ContextMenu>
</ListView.ContextMenu>
</ListView>
The CollectionViewSource is defined as follows:
<DataTemplate x:Key="ListViewListTemplate" DataType="{x:Type ViewModels:ListItemViewModel}">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=DisplayTitle}" Margin="8,0,0,0"/>
</StackPanel>
</DataTemplate>
<CollectionViewSource Source="{Binding Path=ListItemViewModels}" x:Key="ListItemGroups">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="ListItemGroupName"/>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<ComponentModel:SortDescription PropertyName="Index" Direction="Ascending"/>
<ComponentModel:SortDescription PropertyName="DisplayTitle" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<GroupStyle x:Key="ListItemGroupStyle">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<!-- The text binding here is refered to the property name set above in the propertyGroupDescrition -->
<TextBlock x:Name="text" Background="{StaticResource DateGroup_Background}" FontWeight="Bold" Text="{Binding Path=Name}"
Foreground="White"
Margin="1"
Padding="4,2,0,2"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<Style x:Key="ListItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a ReconciliationTaskViewModel object.
-->
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ItemsControl.AlternationIndex" Value="1" />
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#EEEEEEEE" />
</MultiTrigger>
</Style.Triggers>
</Style>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题的原因是
ContextMenu
不是ListView
的逻辑树或可视树的一部分,因此RelativeSource
/FindAncestor
不起作用,并且DataContext
不是继承的。我发布了 这个问题的解决方案,可以使用如下:
The cause of the problem is that the
ContextMenu
isn't part of either the logical or visual tree of theListView
, soRelativeSource
/FindAncestor
doesn't work, and theDataContext
is not inherited.I posted a solution to this problem a few months ago, you can use it as follows: