Laden...

DataGrid zeigt beim Hinzufügen mehrerer Zeilen nicht alle an

Erstellt von C#Matze vor 10 Jahren Letzter Beitrag vor 10 Jahren 4.082 Views
C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren
DataGrid zeigt beim Hinzufügen mehrerer Zeilen nicht alle an

Hallo zusammen,

ich habe ein DataGrid, bei dem ich dynamisch Spalten erstelle. Daher kann ich meines Wissens keine ObservableCollection verwenden.

Diesem DataGrid wie folgt neue Zeilen hinzu:

<DataGrid AutoGenerateColumns="True" AutoGeneratingColumn="OnAutoGeneratingColumn" Name="dataGridMain"
EnableRowVirtualization="True" EnableColumnVirtualization="True" IsReadOnly="True"
ItemsSource="{Binding _dvLogMain, Mode=OneWay, UpdateSourceTrigger=Explicit}"></DataGrid>
private DataTable _dtLogMain = new DataTable();

public DataView _dvLogMain
{
	get {
		return _dtLogMain.DefaultView;
	}
}

// ...

DataRow drTableLogMain = _dtLogMain.NewRow();
drTableLogMain.ItemArray = logData.ToArray();

// nur die letzten 100 Einträge anzeigen
_dtLogMain.Rows.InsertAt(dataTableRow, 0);

while (_dtLogMain.Rows.Count > 100)
{
	// ältestes Element entfernen
	_dtLogMain.Rows.RemoveAt(_dtLogMain.Rows.Count - 1);
}

Prinzipiell funktioniert das alles.
Nur wenn ich schnell hintereinander (in einer Schleife) z.B. 2 Zeilen einfüge, dann sehe ich nur die zuerst eingefügte. Die zweite wird nicht angezeigt. Wird dann eine neue Zeile hinzugefügt, taucht die vorher nicht sichtbare Zeile auf, aber die neu hinzugefügte sieht man nicht. usw.

Auch ohne Angabe von "UpdateSourceTrigger" habe ich das gleiche Verhalten.

Woran liegt das bzw. wie macht man das korrekt? (C# WPF, .NET 4.0)

Grüße
Matze

R
212 Beiträge seit 2012
vor 10 Jahren

Hast du es schoneinmal mit dem INotifyPropertyChanged interface versucht?

5.299 Beiträge seit 2008
vor 10 Jahren

machma testweise die Virtualisierung weg.

Der frühe Apfel fängt den Wurm.

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

Hallo

@Robin0: Nein, noch nicht. Das muss ich dann für die DataTable komplett implementieren oder irgendwie nur bei einer Zeilenänderung?
Denn ein WPF-DataGrid implementiert das meines Wissens nicht. Daher weiß ich nicht, inwieweit man das so programmieren kann.

@ErfinderDesRades: Das ändert leider nichts.

5.299 Beiträge seit 2008
vor 10 Jahren

du kannst statt direkt an die DataTable auch an DataTable.DefaultView binden.

Das ist ein Dataview, und da sind dann statt DataRows DataRowviews drinne, und die implementieren InotifyPropertyChanged.

ach - quark - das haste ja schon!

Also dann weiß ich nicht, was der Vorschlag mit Inotifypropertychanged bringen kann

Der frühe Apfel fängt den Wurm.

R
212 Beiträge seit 2012
vor 10 Jahren

Quick INotifyPropertyChanged:

Da wo dein DataTable/DataView drinne is nimmst du das Interface "INotifyPropertyChanged" mit
Einbinden tust du das dann so:



//using System.ComponentModel;
public class DeineClassemit : INotifyPropertyChanged
//oder:
// public class DeineClassemit : BaseClass,  INotifyPropertyChanged
{
        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises the PropertyChanged event for multiple properties.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected virtual void OnPropertyChanged(params string[] e)
        {
            foreach (var prps in e)
            {
                if (this.PropertyChanged != null)
                    this.PropertyChanged(this, new PropertyChangedEventArgs(prps));
            }
        }
}

Und immer wenn sich dein ItemScource änder schreibst du OnPropertyChanged("DerName des ItemScource");. Den UpdateSourceTrigger deine DataGrid.ItemscourceProperty setzt du aus PropertyChanged.

PS: Alle daten die du bindest müssen bei WPF eig ein get besitzen, desshalb scheib einfach ins set das OnPropertychanged("ItemscourceName"); mitrein und dann sollte dein dataGrid mitbekomm dass sich dein Itemscource geändert hat.

Wenn du eine ObservableCollection<T> als Itemscource verwendest benötigst du das nProp.... nicht.

[edit:
Wenn die Zelle die sich ändert an einene Eigenschaft gebunden ist, reicht es das Onprop... für die Eigenschaft aufzurufen an das die Zelle gebunden ist. bsp: Onprpertychanged("Eigenschaftsname hier eintragen")

..
@ErfinderDesRades
Stimmt, dennoch ist nicht immer sicher dass das DataGrid die änderung auch wirklich mitbekommt(Sicher ist sicher und das INotifyPropertyChanged zu kennen schadet bestimmt nicht).

[edit4 ...
Die DataView bindet weder INotifyPropertyChanged noch ICollectionChanged ein


public class DataView : MarshalByValueComponent, IBindingListView , System.ComponentModel.ITypedList, ISupportInitializeNotification

[Edit5
Du könntest INotifyPropertyChanged auf das ListChanged event von der DefaultView setzen

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

Hallo,

vielen Dank, dass du dir die Zeit für deinen Beitrag genommen hast!

Du könntest INotifyPropertyChanged auf das ListChanged event von der DefaultView setzen

Wie genau wird dies umgesetzt? Ich habe INotifyPropertyChanged bisher nie auf ein Event angewendet.

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

Keiner 'ne Idee?

5.299 Beiträge seit 2008
vor 10 Jahren

Ich kann das Fehlverhalten nicht reproduzieren, daher habich keine Idee als die, dass du eine SampleSolution erstellst, wo man das Verhalten sehen kann, und die zippst und anhängst.
geht ein bischen in Richtung [Tutorial] Vertrackte Fehler durch Vergleich von echtem Projekt mit minimalem Testprojekt finden

Der frühe Apfel fängt den Wurm.

R
212 Beiträge seit 2012
vor 10 Jahren

@C#Matze

  1. Übernimm das interface was ich vorhaer gepostet habe in deine Klasse;

  2. Schreib


_dvLogMain.ListChanged += _dvLogMain.ListChanged += (sender, e) => { OnPropertyChanged("_dvLogMain") };

Das wars eigentlich schon

Du wendes tINotifyPropertyChanged ja auch nicht auf sondern in einem event an 😉.

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

Hallo,

danke für die Antwort!

Vielleicht verstehe ich es noch nicht richtig, aber wenn ich _INotifyPropertyChanged("dvLogMain") auf mein DataView anwende, wird dann nicht das komplette DataGrid aktualisiert wie bei dataGridMain.Items.Refresh()?
Denn das wäre viel zu langsam. 🤔

Stimmt. in einem Event!

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

Leider ist das Verhalten unverändert. 😦

Und "ObservableCollection" kann ich vermutlich nicht verwenden, da meine Properties dynamisch erzeugt werden (die Spalten des DataGrids).

R
212 Beiträge seit 2012
vor 10 Jahren

Wenn du die spalten Dynamisch erzeugst is das doch genau das richtige.
AutoGenerateColumns auf True. und fertig ^^.

Ein DataGrid Zeigt sogar die spalten an wen du den Typen dynamisch mit System.Emit.TypeBuilder() erzeugst.

Edit:
Wenn du eine neue liste verwenden willst dass schreibst du ==> MyCollection = new Observablecollection<T>(MyNewCollection);
!Kein Clear und auch keine neuzuweisung mit leerem konstruktor, sonst geht dir die eigenschaft verlorean das neue zeilen vom User erstellt werden können.!

@c# Matze
Zu dem vorletzten beitrag, Es geht schnell mit Inoty... auch bei 20.000 datensätzen.

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

@c# Matze
Zu dem vorletzten beitrag, Es geht schnell mit Inoty... auch bei 20.000 datensätzen.

Stimmt, es ging genauso schnell. Bei mir habe ich leider keine Änderung bemerkt. Zeilen werden auch da nicht alle dargestellt.

IObservableCollection funktioniert dynamisch, was das Binding betrifft?
Ich habe nur Beispiele wie dieses hier gefunden, in dem "FirstName" etc. fest programmiert sind. Bei mir kommen diese Daten aus einer Datenbank.
Das mit "AutoGeneratedColumns" habe ich so umgesetzt, was auch funktioniert. Nur am Binding scheitere ich irgendwie.

5.299 Beiträge seit 2008
vor 10 Jahren

wenn du dich dann in diese Richtung ausgetobt hast, darfst du dich auch wieder an DataGrid zeigt beim Hinzufügen mehrerer Zeilen nicht alle an erinnern, wenn du noch magst.

Der frühe Apfel fängt den Wurm.

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

wenn du dich dann in diese Richtung ausgetobt hast, darfst du dich auch wieder an
>
erinnern, wenn du noch magst.

Stimmt, ganz vergessen.
Ich habe es nun versucht, minimalistisch nachzustellen, aber leider funktioniert dort alles. Vielleicht liegt's auch an der Methode "OnAutogeneratingColumns", mit der ich die automatisch erzeugten Spalten/Zellen formatiere. Ich versuche das zu reproduzieren.

C
C#Matze Themenstarter:in
31 Beiträge seit 2014
vor 10 Jahren

Hallo,

ich schaffe es beim besten Willen nicht, das Verhalten minimalistisch nachzustellen.

Könnte es am "lock" o.ä. ligen, da ich wie folgt darauf zugreife?

public DataView _dvLogMain
{
	get {
		lock (_dtLogMain)
			return _dtLogMain.DefaultView;
	}
}

Ich bin wirklich ratlos.
Ich bemühe mich um eine Demo, aber ob das jemals klappt, weiß ich nicht ...