Binding from within a ResourceDictionary in a Catel WPF UserControl
我正在将WPF应用程序的某些视图和视图模型转换为Catel,作为概念证明。
用户控件之一似乎在运行时未正确绑定到视图模型。我想我理解这是为什么,但是想获得关于最佳补救方法的一些反馈。
代码
我有一个简单的视图,其模型实际上是
需要注意的关键事项:我正在使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <catel:UserControl x:Class="MyApp.PersonTable" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" xmlns:catel="http://catel.codeplex.com" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="200" d:DataContext="{DynamicResource DesignTimeViewModel}"> <UserControl.Resources> <ResourceDictionary> <CollectionViewSource Source="{Binding PersonItems}" x:Key="PersonItemsSource"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="DOB" Direction="Descending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource> <ui:DesignPersonViewModel x:Key="DesignTimeViewModel" /> </ResourceDictionary> </UserControl.Resources> <Grid> <DataGrid ItemsSource="{Binding Source={StaticResource PersonItemsSource}}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" Header="Name" Width="90" ElementStyle="{StaticResource CellRightAlign}" /> <!-- etc..... --> </DataGrid.Columns> </DataGrid> </Grid> </catel:UserControl> |
视图模型在构造函数中接受模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using Catel.MVVM; public class PersonTableViewModel : ViewModelBase { public PersonTableViewModel(ObservableCollection<Person> personItems) { this.PersonItems = personItems } public ObservableCollection<Person> PersonItems { get { return GetValue<ObservableCollection<Person>>(PersonItemsProperty); } set { SetValue(PersonItemsProperty, value); } } public static PropertyData PersonItemsProperty = RegisterProperty("PersonItems", typeof(ObservableCollection<Person>), () => new ObservableCollection<PersonItems>()); } |
问题
在运行时,网格中不会填充任何项目。尽管在设计时,设计视图模型确实可以在设计视图中正确填充网格。
我对问题的根源是否正确?我相信绑定到
假设我是对的,最好的补救方法是什么?
如果我对以上内容是正确的,那么我可以想到一些可能的补救措施,但似乎没有一个是完美的。我很想知道可以接受的最佳实践来纠正这种情况。
-
将
CollectionViewSource 移到后面的代码中;将其公开为依赖项属性。我不喜欢此选项,因为之后无法在XAML中对其进行配置。 -
将
CollectionViewSource 移动到视图模型。我真的不喜欢这个。将WPF组件放在视图模型中会破坏MVVM。 -
将
CollectionViewSource 绑定到原始的DataContext (即模型)。问题在于设计时视图模型将无法正确绑定。1<CollectionViewSource Source="{Binding}" ..... > -
从绑定到视图模型的隐藏代码中公开依赖项属性。更新:这在运行时有效,但是现在在设计时失败(因为网格不包含测试数据。)
1
2
3
4
5
6
7
8---- PersonTable.xaml.cs ----
[ViewToViewModel(MappingType = ViewToViewModelMappingType.ViewModelToView]
public ObservableCollection<PersonItem> PersonItems { get { ... } }
---- PersonTable.xaml ----
<CollectionViewSource Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type PersonTable}}, Path=PersonItems}" ...... >
您的假设都是正确的。 但是有第四种补救方法。 将资源放入网格内,以便您位于ViewModel数据上下文内:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <catel:UserControl x:Class="MyApp.PersonTable" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" xmlns:catel="http://catel.codeplex.com" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="200" d:DataContext="{DynamicResource DesignTimeViewModel}"> <Grid> <Grid.Resources> <ResourceDictionary> <CollectionViewSource Source="{Binding PersonItems}" x:Key="PersonItemsSource"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="DOB" Direction="Descending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource> <ui:DesignPersonViewModel x:Key="DesignTimeViewModel" /> </ResourceDictionary> </Grid.Resources> <DataGrid ItemsSource="{Binding Source={StaticResource PersonItemsSource}}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" Header="Name" Width="90" ElementStyle="{StaticResource CellRightAlign}" /> <!-- etc..... --> </DataGrid.Columns> </DataGrid> </Grid> </catel:UserControl> |