按 DataTemplate 中 ViewModel 的 属性 对 ListView 进行分组
Grouping ListView by Property of ViewModel in DataTemplate
我有一个问题,我已经阅读了很多关于 MVVM 分组的文章都没有解决。
我正在编写 WPF 应用程序。以下是 classes 中与我的问题相关的一些例外情况 - 首先是 MainViewModel:
public class MainViewModel
{
public ObservableCollection<Recipe_OverViewModel> RecipeOverViews {get ; set;}
....[omitted extraneous lines]....
在 MainViewModel 中用作 Recipes 的可观察对象 collection 的 class:
public class Recipe_OverViewModel
{
public Recipe TargetRecipe { get; set; }
public override string ToString()
{
return TargetRecipe.Parent_Name;
}
....[omitted extraneous lines]....
和从数据库中获取的Class,即实际的食谱
public partial class Recipe
{
[Required]
[StringLength(1000)]
public string Parent_Name { get; set; }
[Required]
[StringLength(60)]
public string Recipe_Name { get; set; }
public override string ToString()
{
return Parent_Name;
}
public int CompareTo(object obj)
{
return Parent_Name.CompareTo(((Recipe)obj).Parent_Name);
}
....[omitted extraneous lines]....
每个class都有更多的属性和方法等等,但是这些足以说明我在问什么了。
Recipe_OverViewModel
是显示配方属性的控件 (Recipe_OverView
) 的视图模型。在 MainViewModel
中,我有以下 xaml(从较大的文件中提取):
<Window x:Class="RecipeApp.UI.MainWindow"
....[omitted extraneous lines]....
xmlns:vm="clr-namespace:RecipeApp.UI.ViewModel"
>
<Window.Resources>
<DataTemplate DataType="{x:Type vm:Recipe_OverViewModel}" x:Key="Recipe_DT" x:Name="Recipe_DT">
<control:Recipe_OverView Width="{Binding ActualWidth,ElementName=ListWidth}"/>
</DataTemplate>
<CollectionViewSource x:Key="SortedRecipeOverViews" Source="{Binding RecipeOverViews}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="TargetRecipe"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="TargetRecipe"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
....[omitted extraneous lines]....
<ListView ItemsSource="{Binding Source={StaticResource SortedRecipeOverViews}}"
ItemTemplate="{StaticResource Recipe_DT}">
</ListView>
此列表视图正确显示列表视图中的配方列表,每行包含 Recipe_OverView
控件。但是,我无法使分组正常工作。我想通过与每个 Recipe_OverViewModel
关联的食谱的 Parent_Name 属性 对列表视图进行分组。我的尝试看起来像这样,遵循 Microsoft HowTo:
<ListView Grid.Row="1" Grid.Column="1"
ItemsSource="{Binding Source={StaticResource SortedRecipeOverViews}}"
ItemTemplate="{StaticResource Recipe_DT}"
>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="true">
<Expander.Header>
<TextBlock Text="{Binding Path=ParentName}" />
</Expander.Header>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
但是,我从中得到的只是空的(没有填充 ParentName)headers,因为 collection 中有食谱,并且绑定失败告诉我“ParentName 属性 在 CollectionViewGroupInternal 类型的 object 上找不到。”我得到了扩展按钮,但扩展组中没有任何内容:
我想我明白这意味着绑定正在 Recipe_OverViewModel
中查找 ParentName 属性,但即使我将其作为 属性 添加到 Recipe_OverViewModel
并填充它,我仍然得到这个错误,所以现在我很困惑并有以下问题:
ListView 上的绑定实际上在哪里查找?
我应该如何引导它查看Recipe_OverViewModel.TargetRecipe.ParentName
(或者不可能)?
在这件事上我真的很感激帮助,很多文章都采用了如此简单的例子,我不知道如何将其扩展到我的案例中!
ItemsSource 绑定到 SortedRecipeOverViews,后者又绑定到 RecipeOverViews 集合。
此集合的项目类型是 Recipe_OverViewModel.
而且这种类型没有 ParentName 属性.
有一个 Parent_Name 属性,但不是 Recipe_OverViewModel 类型,而是 Recipe 类型。
Recipe_OverViewModel 类型有一个 属性 这种类型。
一般来说,你有一些混乱的类型、它们的名称和它们的属性、绑定路径。
也许您在主题中复制了错误的内容?
根据我自己的猜测,尝试应用这样的绑定:
<Expander.Header>
<TextBlock Text="{Binding Path=TargetRecipe.Parent_Name}" />
</Expander.Header>
Where is the binding on the ListView
actually looking?
它寻找 CollectionViewGroupInternal
class 的 属性。
这个 class 有一个 Name
属性 那个 returns 你分组的 属性 的值,即 TargetRecipe
,和 Items
属性 returns 属于当前组的对象集合。
因此,如果我正确理解您的设置,您可以尝试绑定到组中第一项的 Parent_Name
属性:
<Expander.Header>
<TextBlock Text="{Binding Items[0].Parent_Name}" />
</Expander.Header>
我有一个问题,我已经阅读了很多关于 MVVM 分组的文章都没有解决。
我正在编写 WPF 应用程序。以下是 classes 中与我的问题相关的一些例外情况 - 首先是 MainViewModel:
public class MainViewModel
{
public ObservableCollection<Recipe_OverViewModel> RecipeOverViews {get ; set;}
....[omitted extraneous lines]....
在 MainViewModel 中用作 Recipes 的可观察对象 collection 的 class:
public class Recipe_OverViewModel
{
public Recipe TargetRecipe { get; set; }
public override string ToString()
{
return TargetRecipe.Parent_Name;
}
....[omitted extraneous lines]....
和从数据库中获取的Class,即实际的食谱
public partial class Recipe
{
[Required]
[StringLength(1000)]
public string Parent_Name { get; set; }
[Required]
[StringLength(60)]
public string Recipe_Name { get; set; }
public override string ToString()
{
return Parent_Name;
}
public int CompareTo(object obj)
{
return Parent_Name.CompareTo(((Recipe)obj).Parent_Name);
}
....[omitted extraneous lines]....
每个class都有更多的属性和方法等等,但是这些足以说明我在问什么了。
Recipe_OverViewModel
是显示配方属性的控件 (Recipe_OverView
) 的视图模型。在 MainViewModel
中,我有以下 xaml(从较大的文件中提取):
<Window x:Class="RecipeApp.UI.MainWindow"
....[omitted extraneous lines]....
xmlns:vm="clr-namespace:RecipeApp.UI.ViewModel"
>
<Window.Resources>
<DataTemplate DataType="{x:Type vm:Recipe_OverViewModel}" x:Key="Recipe_DT" x:Name="Recipe_DT">
<control:Recipe_OverView Width="{Binding ActualWidth,ElementName=ListWidth}"/>
</DataTemplate>
<CollectionViewSource x:Key="SortedRecipeOverViews" Source="{Binding RecipeOverViews}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="TargetRecipe"/>
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="TargetRecipe"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
....[omitted extraneous lines]....
<ListView ItemsSource="{Binding Source={StaticResource SortedRecipeOverViews}}"
ItemTemplate="{StaticResource Recipe_DT}">
</ListView>
此列表视图正确显示列表视图中的配方列表,每行包含 Recipe_OverView
控件。但是,我无法使分组正常工作。我想通过与每个 Recipe_OverViewModel
关联的食谱的 Parent_Name 属性 对列表视图进行分组。我的尝试看起来像这样,遵循 Microsoft HowTo:
<ListView Grid.Row="1" Grid.Column="1"
ItemsSource="{Binding Source={StaticResource SortedRecipeOverViews}}"
ItemTemplate="{StaticResource Recipe_DT}"
>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="true">
<Expander.Header>
<TextBlock Text="{Binding Path=ParentName}" />
</Expander.Header>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
但是,我从中得到的只是空的(没有填充 ParentName)headers,因为 collection 中有食谱,并且绑定失败告诉我“ParentName 属性 在 CollectionViewGroupInternal 类型的 object 上找不到。”我得到了扩展按钮,但扩展组中没有任何内容:
我想我明白这意味着绑定正在 Recipe_OverViewModel
中查找 ParentName 属性,但即使我将其作为 属性 添加到 Recipe_OverViewModel
并填充它,我仍然得到这个错误,所以现在我很困惑并有以下问题:
ListView 上的绑定实际上在哪里查找?
我应该如何引导它查看Recipe_OverViewModel.TargetRecipe.ParentName
(或者不可能)?
在这件事上我真的很感激帮助,很多文章都采用了如此简单的例子,我不知道如何将其扩展到我的案例中!
ItemsSource 绑定到 SortedRecipeOverViews,后者又绑定到 RecipeOverViews 集合。
此集合的项目类型是 Recipe_OverViewModel.
而且这种类型没有 ParentName 属性.
有一个 Parent_Name 属性,但不是 Recipe_OverViewModel 类型,而是 Recipe 类型。
Recipe_OverViewModel 类型有一个 属性 这种类型。
一般来说,你有一些混乱的类型、它们的名称和它们的属性、绑定路径。
也许您在主题中复制了错误的内容?
根据我自己的猜测,尝试应用这样的绑定:
<Expander.Header>
<TextBlock Text="{Binding Path=TargetRecipe.Parent_Name}" />
</Expander.Header>
Where is the binding on the
ListView
actually looking?
它寻找 CollectionViewGroupInternal
class 的 属性。
这个 class 有一个 Name
属性 那个 returns 你分组的 属性 的值,即 TargetRecipe
,和 Items
属性 returns 属于当前组的对象集合。
因此,如果我正确理解您的设置,您可以尝试绑定到组中第一项的 Parent_Name
属性:
<Expander.Header>
<TextBlock Text="{Binding Items[0].Parent_Name}" />
</Expander.Header>