简体   繁体   中英

C# wpf listview binding problem with observable collection

I followed this Tutorial to create an Calendar/Schedule: https://www.codeproject.com/Articles/35490/Creating-the-Microsoft-Outlook-Appointment-View-in The Listview contains 5 Items, source

<!--<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>-->

Now , as i try to replace the hardcoded Items with an observable collection

        <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; }
    }
}

The ListView contains 2 Items (i created 2 for test purpose) but no items are shown cause "Start" and "Finish" are "not found in the ViewModel" .... I tried a static ressource, several relativ sources but i still have troubles to do it the right way.

Could someone pls help me out and show me the correct way ?

This is a simple LV in MVVM. You've got a little mess in naming: just keep to xxxViewModel etc; don't make shortcuts.

I'm pasting simple MVVM example of simple ListView, which is wrapped by an ItemViewModel class and bound by XAML.

If you're not aware of dangers, don't start your job from user controls. They need different treatment and binding.

Intentionally, I wrapped a basic model (databaseentry) object with a ViewModel. In the future, it's easier to update properties and you won't trouble yourself with 'how to add inotifychanged to entityframework'. More boilerplate, but I hope it'll work.

If you don't understand some things, then try to. There are hacks. If you init viewmodel from 'xaml', as I did here, then don't declare datacontext = new AnyViewModel() because you will fail.

In general, I see MVVM as a poor choice. The bindings are a thing that were always lacking in WinForms/QT, and here they are. But since you've got bindings you start to struggle and struggle with communication, then you add and add classes, data classes, services, and bla bla. The more someone goes into templates and generics the more code becomes a mess.

VIEWMODEL (integrated for simplicity):

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));
            }
        }
    }
}

VIEW:

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM