我收到此错误:
System.Windows.Data错误:40:BindingExpression路径错误:在“对象”“ String”(HashCode = 62725275)上找不到“ OpenPopupCommand”属性。 BindingExpression:Path = OpenPopupCommand; DataItem ='字符串'
当我在命令中添加参数时:
OpenPopupCommand = new RelayParamCommand((e) => PopupVisibility(FilterButton) );
VM:
private void PopupVisibility(object sender)
{
Console.WriteLine(sender.ToString());
PopupVisible ^= true;
}
认为,我向“自动生成的Datagrid标头”添加了“过滤器按钮”。现在,我想在单击按钮时打开弹出窗口。但是认为这是行不通的,因为我必须将x:Name按钮传递给Popup PlacementTarget参数。
<Page.DataContext>
<PDB:UsersViewModel x:Name="vm"/>
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--Page Header info content-->
<Grid Grid.Row="0">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="2" Text="{Binding ElementName=userPage, Path=Name}"/>
<TextBlock Margin="2" Text="{Binding SelectedUser.Name}"/>
<TextBlock Margin="2" Text="{Binding ElementName=myGrd, Path=CurrentColumn.DisplayIndex}"/>
<Button x:Name="mybtn"
Content="{Binding Filters.Count, Mode=OneWay}"
Visibility="{Binding Filters.Count, Converter={Wpf:VisibilityConverter}}"
/>
</StackPanel>
</Grid>
<!--Datagrid content-->
<DataGrid x:Name="myGrd"
SelectionMode="Single"
SelectionUnit="Cell"
CurrentItem="{Binding SelectedUser, Mode=TwoWay}"
CurrentColumn="{Binding CurrentColumn, Mode=TwoWay}"
IsReadOnly="True"
Grid.Row="1"
ItemsSource="{Binding FilteredUserList}"
AutoGenerateColumns="True"
CanUserAddRows="False"
>
<DataGrid.Resources>
<!--Popup-->
<ContextMenu x:Key="ContextMenu">
<ContextMenu.Items>
<MenuItem Header="Filter by Selection" Command="{Binding IncludeCommand, Source={x:Reference vm}}"/>
<MenuItem Header="Filter exclude Selection" Command="{Binding ExcludeCommand, Source={x:Reference vm}}"/>
<MenuItem Header="Remove all Filters" Command="{Binding RemoveAllFiltersCommand, Source={x:Reference vm}}" Visibility="{Binding Filters.Count, Source={x:Reference vm}, Converter={Wpf:VisibilityConverter}}"/>
</ContextMenu.Items>
</ContextMenu>
<!--Custom Datagrid header View-->
<Style TargetType="DataGridColumnHeader" x:Name="FilterHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBox Margin="0,0,0,10" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}, Path=Width}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" HorizontalAlignment="Center"/>
<Button Name="FilterButton"
Content="[-F-]"
Command="{Binding OpenPopupCommand}"
CommandParameter="{Binding ElementName=FilterButton}"/>
<Popup Name="MyPopup"
StaysOpen="False"
Placement="Right"
IsOpen="{Binding PopupVisible}"
PlacementTarget="{Binding FilterButton}">
<Border Background="White" BorderBrush="Black" Padding="5" BorderThickness="2" CornerRadius="5">
<StackPanel Orientation="Vertical">
</StackPanel>
</Border>
</Popup>
</StackPanel>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ContextMenu" Value="{StaticResource ContextMenu}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</Grid>
通过这种方法,我想将clicked按钮作为参数传递给VM,并将其绑定到Popup PlacementTarget参数。我做错了什么?我可以传递点击按钮参数吗?我知道将视图传递给vm时会打破mvvm规则,但是当我不想在datagrid中定义每一列时如何实现我想要的。谢谢
答案 0 :(得分:1)
您的绑定将DataContext
的{{1}}作为源,即DataGridColumnHeader
的值。在您的情况下,该值为DataGridColumn.Header
,而不是预期的视图模型。这就是为什么您的绑定无法解析并且您收到错误消息的原因(准确地告诉您这一点)。
要修复绑定,您必须找到具有必需的string
的下一个父元素,我假定DataContext
:
DataGrid
检查代码时,我可以看到绑定到<Button Name="FilterButton"
Content="[-F-]"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.OpenPopupCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
的命令是 togging 的Button
属性。因此,我建议从视图模型中删除与视图相关的代码,并将PopupVisible
替换为直接绑定到Button
的{{1}}:
ToggleButton
要获取单个列中包含的所有行的单元格值,其中列标题值是参数并映射到属性名称,则需要进行反射。您需要将Popup.IsOpen
绑定到结果列值集合,该集合使用 <!--Custom Datagrid header View-->
<Style TargetType="DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBox Margin="0,0,0,10"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}, Path=Width}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"
HorizontalAlignment="Center" />
<ToggleButton Name="FilterButton"
Content="[-F-]" />
<Popup Name="MyPopup"
StaysOpen="False"
Placement="Right"
IsOpen="{Binding ElementName=FilterButton, Path=IsChecked}"
PlacementTarget="{Binding ElementName=FilterButton}">
<Border Background="White"
BorderBrush="Black"
Padding="5"
BorderThickness="2"
CornerRadius="5">
<StackPanel Orientation="Vertical">
</StackPanel>
</Border>
</Popup>
</StackPanel>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
向项目添加ListView
。最终版本应如下:
ItemTemplate
要将过滤器列表映射到实际项目,需要使用其他类型来保存信息:
Predicate.cs
CheckBox
您还需要为过滤器视图添加一个集合,并为视图模型添加一个包含项的索引:
UsersViewModel.cs
<!--Custom Datagrid header View-->
<Style TargetType="DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBox Margin="0,0,0,10"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridColumnHeader}}, Path=Width}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}}"
HorizontalAlignment="Center" />
<ToggleButton Name="FilterButton"
Content="[-F-]"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.(UsersViewModel.GenerateFilterViewItemsCommand)}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridColumnHeader}, Path=Content}" />
<Popup Name="MyPopup"
StaysOpen="False"
Placement="Right"
IsOpen="{Binding ElementName=FilterButton, Path=IsChecked}"
PlacementTarget="{Binding ElementName=FilterButton}">
<Border Background="White"
BorderBrush="Black"
Padding="5"
BorderThickness="2"
CornerRadius="5">
<ListView
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.(UsersViewModel.FilterViewItems)}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsIncluded, Mode=OneWayToSource}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=DataContext.(UsersViewModel.IncludeItemCommand)}"
CommandParameter="{Binding}" />
<ContentPresenter Content="{Binding CellValue}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
</Popup>
</StackPanel>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
答案 1 :(得分:0)
尝试以下方法:
为页面或DataGrid命名,并将Binding更改为
<MenuItem Command="{Binding Path=DataContext.IncludeCommand, Source={x:Reference myPage}}"/>
答案 2 :(得分:0)
由于您正在自动生成列,因此我强烈怀疑它试图在OpenPopupCommand
的项目的字符串属性之一中找到FilteredUserList
。