代码之家  ›  专栏  ›  技术社区  ›  Mark Denom

如何绑定自定义用户控件的数据

  •  -1
  • Mark Denom  · 技术社区  · 7 年前

    所以我只是设置了一个项目并添加了一个像这样的自定义用户控件。

    <Grid>
            <ItemsControl ItemsSource="{Binding UserViewModel.Users}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <controls:UserCard/>
                            <TextBlock Text="{Binding Name}"/>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
    
            </ItemsControl>
        </Grid>
    

    如你所见,我试着把 Text 属性buti它不绑定。 现在可能有很多原因来解释它为什么会这样做,所以我会尽量缩小范围。

    我已经创建了一个BaseViewModel,它将保存我的ViewModel,它看起来像这样。

    public class BaseViewModel : ObservableObject
        {
            public UserViewModel UserViewModel { get; set; } = new UserViewModel();
        }
    

    然后我把我的视图模型设置成这样

    public class UserViewModel : ObservableObject
        {
            public ObservableCollection<User> Users { get; set; } = new ObservableCollection<User>();
    
            public UserViewModel()
            {
                Users.Add(new User{Name = "Riley"});
                Users.Add(new User{Name = "Riley1"});
            }
        }
    

    很简单,现在我有了一个可观察的对象,它看起来像这样,处理INPC

    public class ObservableObject : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            [NotifyPropertyChangedInvocator]
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    在我的 MainView.xaml 我把数据上下文设置成这样

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new BaseViewModel();
        }
    }
    

    对用户控件来说完全一样

    这就是我添加用户控件的地方,它显示在主窗口中

    <ItemsControl ItemsSource="{Binding UserViewModel.Users}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <controls:UserCard/>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
    
        </ItemsControl>
    

    现在问题是它没有绑定数据,我想显示 Name 属性来自模型,但它不显示它,我不知道为什么,如果我尝试将它直接绑定到主视图中的textBlock属性,它会正常工作。

    我不确定它为什么会这样,我想知道为什么。 我需要利用DependencyProperties吗?或者只是我创建了一个新的baseViewModel实例?我哪里出错了?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Mark Feldman    7 年前

    你的 MainViewWindow 包含带有绑定的项控件 ItemsSource="{Binding UserViewModel.Users}" ,每个项目都显示一个 <controls:UserCard/> . 但是您的用户控件正在尝试用再次绑定到列表 "{Binding UserViewModel.Users}" . 为什么要在另一个列表中显示列表?

    我怀疑这里的问题是您认为您的自定义用户控件 DataContext 仍然指向baseViewModel,就像它的父级一样。不是这样。 数据上下文 一个itemscontrol中的每个项都指向它在列表中自己的关联元素,即类型的实例 User .

    更新:假设您有一个主视图模型,其中包含子视图模型列表,如下所示:

    public class MainViewModel : ViewModelBase
    {
        public MyChildViewModel[] MyItems { get; } =
        {
            new MyChildViewModel{MyCustomText = "Tom" },
            new MyChildViewModel{MyCustomText = "Dick" },
            new MyChildViewModel{MyCustomText = "Harry" }
        };
    }
    
    public class MyChildViewModel
    {
        public string MyCustomText { get; set; }
    }
    

    假设您将MainWindow的DataContext设置为MainViewModel的一个实例,并添加一个ListView:

    <ListView ItemsSource="{Binding MyItems}" />
    

    如果这样做,您将看到以下内容:

    enter image description here

    这里发生的事情是,listView正在为列表中的三个元素中的每一个创建一个容器(contentpresenter类型),并设置每个元素的dataContext指向其自己的myChildViewModel实例。默认情况下,ContentPresenter只对其DataContext调用“ToString()”,所以您只看到它所指向的类的名称。如果您添加 ToString() MyChildViewModel的运算符如下:

    public override string ToString()
    {
        return $"MyChildViewModel: {this.MyCustomText}";
    }
    

    …然后您将看到显示的内容:

    enter image description here

    您还可以完全重写ListViewItem的模板,因为它已经指向其关联的MyChildViewModel实例,所以您可以直接绑定到其属性:

    <ListView ItemsSource="{Binding MyItems}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <!-- One of these gets created for each element in the list -->
                <Border BorderBrush="Black" BorderThickness="1" Background="CornflowerBlue" CornerRadius="5" Padding="5">
                    <TextBlock Text="{Binding MyCustomText}" Foreground="Yellow" />
                </Border>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    它将把显示更改为:

    enter image description here

    有道理?