【问题标题】:WPF Hierarchical ViewModel FindAncestor data binding errorWPF Hierarchical ViewModel FindAncestor 数据绑定错误
【发布时间】:2013-04-10 22:26:06
【问题描述】:

我正在创建一个 MVVM 应用程序,它有两个视图模型,RegisterUserViewModel 和 UserViewModel。 “RegisterUserViewModel”有一个公共属性,它是“UserViewModel”的集合,如下所示

public class RegisterUserViewModel : ViewModelBase
{
    public ObservableCollection<UserViewModel> Users { get; }
    public ObservableCollection<string> UsersFromAD { get; }
}

public class UserViewModel : ViewModelBase
{
    public string Name { get; set; }
}

“RegisterUserViewModel”类还有一个“UsersFromAD”属性,该属性填充了从 Active Directory 获得的用户名。

我的问题在于我的视图中的数据绑定。

我有一个 MainWindow 视图,它将其窗口分为两个区域(左侧和右侧):左侧区域有可用命令列表,右侧区域有选项卡控件。 左侧的命令用于在选项卡控件上打开新选项卡。 TabControl 的 ItemsSource 属性绑定到“ViewModelBase”类的集合。由于 DataTemplate 绑定,TabControl 中每个打开的选项卡都会自动绑定到特定视图,具体取决于打开的类的类型。

让我更清楚:

1) 我在左侧有一个命令,它将“RegisterUserViewModel”的新实例添加到 TabControl 的 ItemsSource 属性所绑定的“ObservableCollection”。

2) MainWindow.xaml 文件中有一个部分指定了一个 DataTemplate,它将特定视图绑定到 RegisterUserViewModel,如下面的代码所示:

<Window.Resources>
    <ResourceDictionary>
        <DataTemplate DataType={x:Type ViewModel:RegisterUserViewModel}">
            <View:RegisterUserView />
        </DataTemplate>
    <ResourceDictionary>
<Window.Resources>

3) 通过这样做,WPF 会自动将我的 RegisterUserView 的 DataContext 设置为我的 RegisterUserViewModel。

现在,我向我的 RegisterUserView 添加了一个 DataGrid 控件,并将其 ItemsSource 设置为我的 UserViewModel 集合(用户)。一切正常,添加到集合中的用户会显示在 DataGrid 上。

但是,我希望数据网格上的“名称”列使用 DataGridComboBoxColumn,其 ItemsSource 属性设置为位于我的“RegisterUserViewModel”类上的“UsersFromAD”属性。

为此,我使用了以下 xaml:

<DataGridComboBoxColumn ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ViewModel:RegisterUserViewModel}}, Path=UsersFromAD}"
                        SelectedValueBinding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ViewModel:UserViewModel}}, Path=Name}"
                        />

但是,这不起作用。每当我运行应用程序时,我都会从输出窗口中获得以下信息:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='TestApplication.ViewModel.RegisterUserViewModel', AncestorLevel='1''. BindingExpression:Path=UsersFromAD; DataItem=null; target element is 'DataGridComboBoxColumn' (HashCode=24004376); target property is 'ItemsSource' (type 'IEnumerable')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='TestApplication.ViewModel.UserViewModel', AncestorLevel='1''. BindingExpression:Path=Name; DataItem=null; target element is 'TextBlockComboBox' (Name=''); target property is 'SelectedValue' (type 'Object')

谁能帮我正确设置这些绑定?

【问题讨论】:

    标签: wpf data-binding mvvm combobox wpfdatagrid


    【解决方案1】:

    我通过将 CollectionViewSource 添加到我的 RegisterUserView 的“UserControl.Resources”部分并将 CollectionViewSource 绑定到我的 UsersFromAD 属性来解决此问题,如下所示:

    <UserControl.Resources>
        <CollectionViewSource x:Key="cvsUsersFromAD" Source="{Binding UsersFromAD}" />
    </UserControl.Resources>
    

    然后,通过将我的 DataGridComboBoxColumn 绑定到我的 CollectionViewSource,如下所示:

    <DataGridComboBoxColumn ItemsSource="{Binding Source={StaticResource cvsUsersFromAD}}"
                            />
    

    【讨论】:

      【解决方案2】:

      FindAncestor 在 元素树 中搜索类型,而不是在树中元素的 DataContext 中。因此,对于绑定列的 ItemSource,您可以尝试以下操作(据我了解您的对象图)

      <DataGridComboBoxColumn ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type View:RegisterUserView}}, Path=DataContext.UsersFromAD}"
                              />
      

      【讨论】:

      • 当我这样做时,我得到一个编译错误:“错误:类型引用找不到名为'RegisterUserView'的公共类型。
      • @Samir 你有RegisterUserView 类吗?您是否将 xmlns:View 绑定到它所在的命名空间?
      • 我通过修复命名空间声明修复了编译器错误。但是,我仍然收到一个错误:System.Windows.Data 错误:找不到与引用'RelativeSource FindAncestor,AncestorType='TestApplication.View.RegisterUserView',AncestorLevel='1'' 进行绑定的源。 BindingExpression:Path=DataContext.UsersFromAD;数据项=空;目标元素是“DataGridComboBoxColumn”(HashCode=24004376);目标属性是“ItemsSource”(类型“IEnumerable”)
      • 如果删除 AncestorLevel='1' 会发生什么?
      • 我没有明确说 AncestorLevel=1。如果您不通过 XAML 提供任何值,这实际上是 AncestorLevel 的默认值。
      猜你喜欢
      • 2011-05-05
      • 2010-12-10
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 2016-07-16
      相关资源
      最近更新 更多