可观察集合的 C# wpf listview 绑定问题

Posted

技术标签:

【中文标题】可观察集合的 C# wpf listview 绑定问题【英文标题】:C# wpf listview binding problem with observable collection 【发布时间】:2021-12-15 01:55:15 【问题描述】:

我按照本教程创建日历/时间表:https://www.codeproject.com/Articles/35490/Creating-the-Microsoft-Outlook-Appointment-View-in Listview 包含 5 个项目,来源

<ListView.Items>
    <local:Termin Start="10/28/2021 6:00 AM" Finish="10/28/2021 4:00 PM" Subject="Meet with John" Location="Southwest Meeting Room" Organizer="Jim Smith" />
    <local:Termin Start="10/29/2021 6:00 AM" Finish="10/29/2021 4:00 PM" Subject="Meet with Rick" Location="Southwest Meeting Room" Organizer="Jim Smith" />
    <local:Termin Start="10/30/2021 6:00 AM" Finish="10/30/2021 6:00 PM" Subject="Meet with Dave" Location="Southwest Meeting Room" Organizer="Jim Smith" />
    <local:Termin Start="10/31/2021 6:00 AM" Finish="10/31/2021 6:00 PM" Subject="Meet with Larry" Location="Southwest Meeting Room" Organizer="Jim Smith" />
    <local:Termin Start="10/31/2021 6:00 AM" Finish="10/31/2021 6:00 PM" Subject="Meet with Jim" Location="Southwest Meeting Room" Organizer="Jim Smith" />
</ListView.Items>

现在,当我尝试用可观察的集合替换硬编码的项目时

<ListView  ItemsSource="Binding Termine">
    <ListView.View>
        <controls:CalendarView ItemBeginBinding="Binding Start" ItemEndBinding="Binding Finish">
public class KalenderVM : BewohnerVM

    public KalenderVM()
    
        DateTime dateValue1;
        DateTime dateValue2;
        DateTime.TryParse("25.10.2021 6:00", out dateValue1);
        DateTime.TryParse("25.10.2021 16:00", out dateValue2);
        Termine.Add(new Termin(dateValue1, dateValue2, "Jan", "Anker"));
        DateTime.TryParse("26.10.2021 6:00", out dateValue1);
        DateTime.TryParse("26.10.2021 16:00", out dateValue2);
        Termine.Add(new Termin(dateValue1, dateValue2, "Jan", "Anker"));
        DateTime.TryParse("27.10.2021 6:00", out dateValue1);
        DateTime.TryParse("27.10.2021 18:00", out dateValue2);
        Termine.Add(new Termin(dateValue1, dateValue2, "Jan", "Frei"));
    

    private ObservableCollection<Termin> _termine = new ObservableCollection<Termin>();
    public ObservableCollection<Termin> Termine
    
        get  return _termine; 
        set  _termine = value; 
    
...

public partial class Kalender : UserControl

    public Kalender()
    
        InitializeComponent();
    

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IWHRManagment.Models

    public class Termin
    
        public Termin(DateTime start, DateTime finish, string orga, string sub)
        
            Start = start;
            Finish = finish;
            Organizer = orga;
            Subject = sub;
            Location = "Home";
        
        public Termin()  
        public DateTime Start  get; set; 
        public DateTime Finish  get; set; 
        public bool Recurring  get; set; 
        public object Interval  get; set; 
        public string Organizer  get; set; 
        public string Subject  get; set; 
        public string Location  get; set; 
    

ListView 包含 2 个项目(我为测试目的创建了 2 个),但没有显示任何项目,因为“在 ViewModel 中找不到”“开始”和“完成”......我尝试了一个静态资源,几个相对源但我仍然很难以正确的方式做到这一点。

有人可以帮助我并告诉我正确的方法吗?

【问题讨论】:

请发布您的代码隐藏(ViewModel、C# 代码),而不仅仅是标记。如果我们看不到 ViewModel,我们无法告诉您为什么 ViewModel 中缺少属性 添加了模型、代码隐藏和虚拟机。 controls:CalendarView 来自哪里,在您的&lt;ListView.View&gt; 中?您永远不会定义 CalendarView,但据说其中定义了名为 ItemBeginBindingItemEndBinding 的属性。另外,你的 DataContext 设置了吗?在这种情况下,您的构造函数中必须有类似 DataContext = this 的内容或类似的 KalenderVM 【参考方案1】:

这是 MVVM 中的一个简单 LV。您的命名有点混乱:请保留xxxViewModel 等;不要走捷径。

我正在粘贴简单 ListView 的简单 MVVM 示例,它由 ItemViewModel 类包装并由 XAML 绑定。

如果您没有意识到危险,请不要从用户控件开始您的工作。它们需要不同的处理和绑定。

我有意用 ViewModel 包装了一个基本模型(数据库条目)对象。将来,更新属性会更容易,您不会为“如何将 inotifychanged 添加到实体框架”而烦恼。更多样板,但我希望它会起作用。

如果你不明白一些事情,那就试着去。有黑客。如果您像我在这里所做的那样从“xaml”初始化视图模型,那么不要声明datacontext = new AnyViewModel(),因为您将失败。

总的来说,我认为 MVVM 是一个糟糕的选择。绑定是 WinForms/QT 中一直缺少的东西,现在它们就在这里。但是,既然你有了绑定,你就开始在通信中挣扎和挣扎,然后你添加和添加类、数据类、服务和 bla bla。越有人进入模板和泛型,代码就越混乱。

VIEWMODEL(为简单起见集成):

using Pjoter2000.View;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pjoter2000.ViewModel

    public class DatabaseEntry // EntityFramework as an example
    
        public int ID  get; set; 
        public string DataName  get; set; 
    

    // MVVM wrapper for single item, Inotifypropertychanged should be a class that simplifiesr wrapping
    public class SomeItemViewModel : INotifyPropertyChanged
    
        public event PropertyChangedEventHandler? PropertyChanged;

        private DatabaseEntry _item;

        public string Name
        
            get => _item.DataName;
            set
            
                _item.DataName = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
            
        

        SomeItemViewModel()   //wtf? :)

        public SomeItemViewModel(DatabaseEntry entry)
        
            _item = entry;
        
    

    public class PoligonViewModel
    
        ObservableCollection<SomeItemViewModel> _records;
        public ObservableCollection<SomeItemViewModel> Records
        
            get => _records;
            set
            
                _records = value;
            
        

        public PoligonViewModel()
        
            // INIT Records
            Records = new ObservableCollection<SomeItemViewModel>();

            // Fetching data from model (DB), abstract
            for (int i = 0; i < 10; i++)
            
                var item = new DatabaseEntry()
                
                    DataName = "Name " + i.ToString()
                ;

                // Wrapping database model data into itemviewmodel (some say it's more flexible and might be ok in future)
                Records.Add(new SomeItemViewModel(item));
            
        
    

查看:

using System.Windows;

namespace Pjoter2000.View

    public partial class Poligon : Window
          
        public Poligon()
        
            InitializeComponent(); // Current data context is poligonviewmodel, because it's set from xaml already           
        
    

XAML

<Window x:Class="Pjoter2000.View.Poligon"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewmodel="clr-namespace:Pjoter2000.ViewModel"
        mc:Ignorable="d"
        Title="Poligon" Height="400" Width="514">

    <Window.DataContext>
        <!-- THIS PART CREATES VIEW MODEL CLASS, DON'T CREATE IT IN CONSTRUCTOR -->
        <viewmodel:PoligonViewModel/>
    </Window.DataContext>
    <Grid>
        <ListView ItemsSource="Binding Records">
            <!-- This is the main view of the list, so I declare the view here -->
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="Binding Name"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Window>

【讨论】:

以上是关于可观察集合的 C# wpf listview 绑定问题的主要内容,如果未能解决你的问题,请参考以下文章

WPF ListView在运行时不更新

WPF ListView - 2 个维度,1 个相同的结构

为啥我的 ListView 数据绑定到可观察集合不能正确显示

WPF ListView 忽略 SelectedItem-change

如何将 TabControl 的项目绑定到 wpf 中的可观察集合?

刷新 WPF Datagrid 未绑定到可观察集合?