Laden...

DataGidView DataBinding WPF wahrscheinlich Verständnisproblem

Erstellt von Sindelfinger vor 3 Jahren Letzter Beitrag vor 3 Jahren 520 Views
S
Sindelfinger Themenstarter:in
39 Beiträge seit 2019
vor 3 Jahren
DataGidView DataBinding WPF wahrscheinlich Verständnisproblem

Liebes Forum,

derzeit bin ich dabei, eine WinForms - Anwendung ein bißchen aufzuhübschen und auf WPF zu übertragen. Im alten Projekt habe ich mir im Hauptbildschirm Spielstände mitgeschrieben in eine dort lokale Liste die aus Einträgen meiner Klasse(das Types böse sind, habe ich hier im Forum gelernt 😄) "MatchHistory" besteht.

Dann das Ganze über die Schnittstelle in mein Ergebnisformular geladen und dort mit einer ListView angezeigt. So weit - so gut.

Der neue Plan ist das ganze mit einem DataGridView anzuzeigen, das aber eine Datenbindung zu dieser Klasse hat.

In diesem Beitrag wurde das Thema angeschnitten und ich habe nach diesem Muster eine MatchHistoryViewModel - Klasse erstellt.

Jetzt fehlt mir wohl nur noch ein kleines Stück:

Ich habe eine lokale Variable vom Typen dieser Klasse erstellt:


private MatchHistoryViewModel _myMatchView = new MatchHistoryViewModel(); 
public MatchHistoryViewModel myMatchView
{
     get { return _myMatchView; }
     set 
     {
          _myMatchView = value;
     }
}


Beim Starten meines MainWindows füttere ich das mit Daten:

 
private void Test2()
{         
    foreach (string s in Enum.GetNames(typeof(MatchNames)))
   {
         MatchViewModel mv = new MatchViewModel
         { 
                ID=0,
                GameName=s,
                Sets2Play=3,
                SetsPlayed=0,
                Score0=0,
                Score1=0,
                Player1="Vika",
                Player2="Roli"
          };
          _myMatchView.AddEntry(mv);
     }
        
}

Anhand des Beispiels in dem o.a. Artikel habe ich dann versucht, die Bindung herzustellen.

<Window x:Class="ListViewBinding.MainWindow"   
    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:local="clr-namespace:ListViewBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MatchHistoryViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <DataGrid x:Name="Match" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding _myMatchview}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Width="50" Binding="{Binding ID}"/>
                <DataGridTextColumn Header="Game" Width="150" Binding="{Binding GameName}"/>
                <DataGridTextColumn Header="Sets" Width="100" Binding="{Binding Sets2Play}"/>
                <DataGridTextColumn Header="Played" Width="100" Binding="{Binding SetsPlayed}"/>
            </DataGrid.Columns>
        </DataGrid>

Aber da kommt die Fehlermeldung: > Fehlermeldung:

Schweregrad Anzahl Datenkontext Bindungspfad Ziel Zieltyp Beschreibung Datei Zeile Projekt
Fehler 1 MatchHistoryViewModel _myMatchview DataGrid.ItemsSource, Name="Match" IEnumerable Die Eigenschaft "_myMatchview" wurde im Objekt vom Typ "MatchHistoryViewModel" nicht gefunden.

Es ist ja nicht so, daß es ich das dringend brauche. Aber verstehen möchte ich das Ganze endlich. Wahrscheinlich ist der Denkfehler riesig oder winzig.

Und nach der zweiten schlaflosen Nacht deswegen gehe ich jetzt heia.

Off Topic: Für alle ein gesundes neues Jahr.

2 stupid 4 chess? No way.
2 stupid 4 C#? It seems so X(

U
69 Beiträge seit 2019
vor 3 Jahren

_myMatchview kann nicht gefunden werden weil es private ist.
Du musst an myMatchview binden.
Das solltest du auch noch nach MyMatchview umbenennen.

[EDIT]
Und so wie es aussieht suchst du im MatchHistoryViewModel nach dem _myMatchview . _myMatchview ist aber selbst das MatchHistoryViewModel. Da müsstest du das Binding für das Window auch noch anpassen.

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
P
441 Beiträge seit 2014
vor 3 Jahren

Ein Binding muss bei WPF immer auf eine Property gehen, niemals auf eine Member Variable.

Wenn trotzdem noch nichts angezeigt wird, benötigst du INotifyPropertyChanged in deinem ViewModel, wenn du Veränderungen im Code an der gebundenen Collection machen willst, sollte es eine ObservableCollection sein.

5.657 Beiträge seit 2006
vor 3 Jahren

Hier gibt es eine ausführliche Einführung in MVVM mit Code-Beispielen: [Artikel] MVVM und DataBinding

Weeks of programming can save you hours of planning

S
Sindelfinger Themenstarter:in
39 Beiträge seit 2019
vor 3 Jahren

Wenn trotzdem noch nichts angezeigt wird, benötigst du INotifyPropertyChanged in deinem ViewModel, wenn du Veränderungen im Code an der gebundenen Collection machen willst, sollte es eine ObservableCollection sein.

 
public class MatchHistoryViewModel : ViewModelBase
    { 
        public ObservableCollection<MatchViewModel> MatchHistory { get; }
        public MatchHistoryViewModel()
        {
            MatchHistory = new ObservableCollection<MatchViewModel>();
        }
        public void AddEntry(MatchViewModel i)
        {
     
            MatchHistory.Add(i);
        }    
    }

So hab ich es ja auch gemacht. Auch ein PropertyChangedEventhandler ist vorhanden, der im MatchviewModel auch brav gefeuert wird.

Da müsstest du das Binding für das Window auch noch anpassen.

Sehr gerne - aber wie?

<Window x:Class="ListViewBinding.MainWindow"   
    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:local="clr-namespace:ListViewBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MatchHistoryViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <DataGrid x:Name="Match" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding MatchHistory}" AutoGenerateColumns="True" Margin="-23,0,22.8,0" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Width="50" Binding="{Binding ID}"/>
                <DataGridTextColumn Header="Game" Width="150" Binding="{Binding GameName}"/>
                <DataGridTextColumn Header="Sets" Width="100" Binding="{Binding Sets2Play}"/>
                <DataGridTextColumn Header="Played" Width="100" Binding="{Binding SetsPlayed}"/>
            </DataGrid.Columns>
        </DataGrid>   
    </Grid>
    
</Window>

So, und nun zeigt's was an. Ich habe in mein Modul "Test2" einfach am Ende eingefügt

Match.DataContext = MyMatchView

. Jetzt zeigt mir das DGV mit Ausnahme der ID alles an, und wenn ich Einträge editiere, werden auch brav die Ereignisse gefeuert.

Erstmal herzlichen Dank für die Antworten. Hat wer eine Idee, warum die ID nicht angezeigt wird?

Hier nochmal die MatchHistory - Klasse:


     public class MatchViewModel : ViewModelBase
    {

        private int _ID;
        private string _GameName;
        private int _Sets2Play;
        private int _SetsPlayed;
        private int _Score0;
        private int _Score1;
        private string _Player1;
        private string _Player2;

        public int ID
        {
            get { return _ID; }
            set
            {
                _ID = value;
                RaisePropertyChanged(nameof(ID));
            }
        }
        public string GameName
        {
            get { return _GameName; }
            set
            {
                _GameName = value;
                RaisePropertyChanged(nameof(GameName));
            }
        }
        public int Sets2Play
        {
            get { return _Sets2Play; }
            set
            {
                _Sets2Play = value;
                RaisePropertyChanged(nameof(_Sets2Play));
            }
        }
        public int SetsPlayed
        {
            get { return _SetsPlayed; }
            set
            {
                _SetsPlayed = value;
                RaisePropertyChanged(nameof(SetsPlayed));
            }
        }
        public int Score0
        {
            get { return _Score0; }
            set
            {
                _Score0 = value;
                RaisePropertyChanged(nameof(Score0));
            }
        }
        public int Score1
        {
            get { return _Score1; }
            set
            {
                _Score1 = value;
                RaisePropertyChanged(nameof(Score1));
            }
        }
        public string Player1
        {
            get { return _Player1; }
            set
            {
                _Player1 = value;
                RaisePropertyChanged(nameof(Player1));
            }
        }
        public string Player2
        {
            get { return _Player2; }
            set
            {
                _Player2 = value;
                RaisePropertyChanged(nameof(Player2));
            }
        }
        
    }
    public class MatchHistoryViewModel : ViewModelBase
    { 
        public ObservableCollection<MatchViewModel> MatchHistory { get; }
        public MatchHistoryViewModel()
        {
            MatchHistory = new ObservableCollection<MatchViewModel>();
        }
        public void AddEntry(MatchViewModel i)
        {
     
            MatchHistory.Add(i);
        }    
    }
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            // Führt das Event aus und gibt den Property-Namen als Argument mit, damit WPF reagieren kann.
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

[EDIT] Auch das hat sich erledigt. Es hat sich eine negative Margin eingeschlichen (-46). Das ganze auf Null und fertig war's [/EDIT]

2 stupid 4 chess? No way.
2 stupid 4 C#? It seems so X(

S
Sindelfinger Themenstarter:in
39 Beiträge seit 2019
vor 3 Jahren

Hier gibt es eine ausführliche Einführung in MVVM mit Code-Beispielen:
>

Herzlichen Dank. Diese Einführung habe ich mir im Vorfeld zu Gemüse geführt und - offensichtlich - nicht alles verstanden. Also arbeite ich das noch ein zweites mal durch.

2 stupid 4 chess? No way.
2 stupid 4 C#? It seems so X(

5.657 Beiträge seit 2006
vor 3 Jahren

Wenn es einen Bindingfehler gibt, steht der während der Ausführung im Ausgabefenster bzw. auch (in VS 2019) im Fenster für die WPF-Bindingfehler.

Ansonsten kannst du dir die Inhalte im Live Visual Tree anschauen bzw. mit einem DebugConverter. Siehe dazu den Abschnitt "Debugging" im MVVM-Artikel.

Weeks of programming can save you hours of planning

S
Sindelfinger Themenstarter:in
39 Beiträge seit 2019
vor 3 Jahren

Das wonach ich tagelang gesucht habe, habe ich hier im Forum gefunden. Herzlichen Dank an alle.

Und jetzt stoße ich auf dieses Video. Ein paar Tage zu spät.

Super erklärt anhand eines Beispiels.

2 stupid 4 chess? No way.
2 stupid 4 C#? It seems so X(