【问题标题】:Populate ListView using custom DataTemplate and dynamic data使用自定义 DataTemplate 和动态数据填充 ListView
【发布时间】:2018-07-31 19:42:44
【问题描述】:

我有一个想要在 XAML 中填充的 ListView。我正在使用自定义 DataTemplate 使添加的每个 ListViewItem 包含一个标签和一个 TextBlock。

问题是我需要使用设置属性中的数据动态填充每个 ListViewItem 的 TextBlock 的文本,而我不知道如何创建此绑定。

现在我正在使用 XmlDataProvider 填充 ListView,但我无法(或至少无法弄清楚如何)将值绑定到 xml 数据。 (我并没有卡在使用这种数据填充方法,这正是我遇到这个问题时最初在做的事情。)

基本上我需要以下内容: 用户在文本框中输入一些数据。该数据将保存到用户设置中。发生这种情况时,ListView 中的 ListViewItem 对应的 TextBlock 会使用用户设置数据进行更新。

通常我会将 TextBlock 的文本绑定到用户设置,如下所示:

Text="{Binding Source={x:Static properties:Settings.Default},Path=User_Data_1}"

但是当 TextBlock 的文本在 DataTemplate 中定义时,我该怎么做呢?

我的 DataTemplate 和 XmlDataProvider:

    <DataTemplate x:Key="listViewTemplate">
        <StackPanel Orientation="Vertical">
            <Label x:Name="lblName" Content="{Binding XPath=name}"/>
            <TextBlock x:Name="tbValue" Text="{Binding XPath=value}"/>
        </StackPanel>
    </DataTemplate>

    <XmlDataProvider x:Key="PagesData" XPath="Pages">
        <x:XData>
            <Pages xmlns="">
                <page id="page01">
                    <name>Text file:</name>
                    <value></value>
                    <source>Pages/Page_CreateFiles1.xaml</source>
                </page>
                <page id="page02">
                    <name>Xml file:</name>
                    <value></value>
                    <source>Pages/Page_CreateFiles2.xaml</source>
                </page>
                <page id="page03">
                    <name>Memory object database:</name>
                    <value></value>
                    <source>Pages/Page_CreateFiles3.xaml</source>
                </page>
                <page id="page04">
                    <name>Output database:</name>
                    <value></value>
                    <source>Pages/Page_CreateDB.xaml</source>
                </page>
            </Pages>
        </x:XData>
    </XmlDataProvider>

我的列表视图

<ListView x:Name="lvNavigation" 
          ItemTemplate="{DynamicResource listViewTemplate}"
          ItemsSource="{Binding Source={StaticResource PagesData}, XPath=page}"/>

【问题讨论】:

    标签: wpf xaml data-binding


    【解决方案1】:

    创建一个包含项目集合的视图模型

    public class Item
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }
    
    public class ViewModel
    {
        public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
    }
    

    并将 MainWindow 的 DataContext 设置为视图模型类的实例

    public MainWindow()
    {
        InitializeComponent();
    
        var vm = new ViewModel();
        DataContext = vm;
    
        vm.Items.Add(new Item { Name = "Name 1", Value = "Value 1" });
        vm.Items.Add(new Item { Name = "Name 2", Value = "Value 2" });
    }
    

    像这样绑定它:

    <ItemsControl ItemsSource="{Binding Items}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Name}"/>
                    <TextBlock Text="{Binding Value}"/>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    【讨论】:

    • 看起来它会起作用,但我希望能够在 XAML 中做到这一点。有任何想法吗?另外,如果我这样做,我将如何绑定到我的设置属性?
    • 不确定“绑定到我的设置属性”到底是什么意思。不是关于物品集合的问题吗?所以你想绑定到多个设置属性?不是有可变数量的项目吗?否则,ItemsControl 会很有意义。
    • 好吧,我想我不会再绑定了,因为它不是通过 XAML。我只是将它设置为设置属性。我只是想绑定,因为这就是我想要做的,使用 xaml 绑定在列表视图中填充列表视图项的属性。
    • 我想我的意思是,谢谢你的回答,这完全有效,干得好,我明白你的提议......这不是我想做的哈哈也许我正在尝试做的事情是不可能的。我不知道,如果我没有收到任何其他建议,我会在一天内将您的帖子标记为答案。
    • 绑定到像User_Data_1 这样的特定设置属性与“数据模板”的概念相矛盾,“数据模板”是在运行时提供的数据模板。但是,您可以从一组 Settings 属性中填充 Items 集合,当然还可以在运行时添加、编辑和删除项目。
    【解决方案2】:

    Clemmens 的回答是正确的,但我只是想把它放在那里,我基本上做了他的方法,稍作修改。我使用事件来触发列表视图中的数据更改。

    我认为这是我自己的错,因为我没有很好地解释我的问题。首先,我想从 xaml 做所有事情,但我认为这是不可能的。其次,我没有提到我在框架中使用页面,其中数据来自页面,而列表视图位于包含框架的主窗口中。所以这就是我最终使用事件在页面和主窗口之间进行通信的原因。

    所以在我的主窗口中我定义了我的 observable 集合:

        ObservableCollection<NavItem> NavItems = new ObservableCollection<NavItem>();
    
        public MainWindow()
        {
            InitializeComponent();
    
            NavItems.Add(new NavItem { Name = "Text file:", Value = "", Source = "Pages/Page_CreateFiles.xaml" });
            NavItems.Add(new NavItem { Name = "Xml file:", Value = "", Source = "Pages/Page_CreateFiles.xaml" });
            NavItems.Add(new NavItem { Name = "Memory object db:", Value = "", Source = "Pages/Page_CreateFiles.xaml" });
            NavItems.Add(new NavItem { Name = "Output database:", Value = "", Source = "Pages/Page_CreateDB.xaml" });
    
            lvNavigation.ItemsSource = NavItems; 
    
            ...
    
        }
    

    “NavItem”是一个订阅 INotifyPropertyChanged 的​​类。发布该代码会很多,因此请在此处查看如何执行此操作:INotifyPropertyChanged

    然后在每个页面中我设置一个事件,我用要发送的数据调用它:

        public static event EventHandler<NavUpdateMessage> UpdateMessage;
    
        private void OnUpdateMessage(int id, string message)
        {
            NavUpdateMessage navUpdateMessage = new NavUpdateMessage();
            navUpdateMessage.Id = id;
            navUpdateMessage.Message = message;
    
            var e = UpdateMessage;
    
            if (e != null)
                e(this, navUpdateMessage);
        }
    

    主窗口订阅了该事件:

        public MainWindow()
        {
            ...
    
            Pages.Page_CreateFiles.UpdateMessage += Pages_UpdateMessage;
            Pages.Page_CreateDB.UpdateMessage += Pages_UpdateMessage;
        }
    
        private void Pages_UpdateMessage(object sender, NavUpdateMessage e)
        {
            Dispatcher.BeginInvoke(new Action(() =>
            {
                NavItems[e.Id].Value = e.Message;
            }));
        }
    

    我确信有更好、更简单的方法来解决这个问题,但这是我能想到的。即使我确定没有人会看到这个,因为这个问题肯定没有引起任何关注,但请随时提出更好的解决方案,这样至少我可以学习。

    【讨论】:

      猜你喜欢
      • 2015-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-18
      • 2017-08-21
      • 2022-01-03
      • 1970-01-01
      相关资源
      最近更新 更多