Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
WPF DataGrid - Refresh single Item
ChristianAT
myCSharp.de - Member



Dabei seit:
Beiträge: 2

Themenstarter:

WPF DataGrid - Refresh single Item

beantworten | zitieren | melden

Hallo Community,

Ich habe ein WPF DataGrid das ich mit einer ObservableCollection<T> fülle.
Die Daten bekomme ich von einem WCF Service.


dgMitarbeiter.ItemsSource = new ObservableCollection<Mitarbeiter>(_wcfService.MitarbeiterGet());

Wenn ich nun Änderungen an einem Objekt per DataGrid mache, gebe ich das geändert Objekt zurück an den WCF Service.
Der WCF Service macht dann Berechnungen etc. und ändert das Objekt weiter ab (Properties werden gesetzt etc.)


_wcfService.MitarbeiterUpdate(dgMitarbeiter.SelecteItem as Mitarbeiter);

Nun möchte ich alle Änderungen die der WCF Service gemacht hat in meinem DataGrid sehen.
Ich möchte aber nicht ItemsSource nochmal setzten, da die Liste riesig ist und die Selektierungen, expanded rowDetails, sortierung, focus etc. verloren geht.
Das alles zu speichern und nach dem refresh wieder zu setzten kann nicht die Lösung sein.

Mein erfolgloser Versuch, das geänderte Objekt zu übernehmen:


((ObservableCollection<Mitarbeiter>)(dgMitarbeiter.ItemsSource))[ix] = _wfcService.MitarbeiterGetById(id);

Wenn ich das so mache, sehe ich zwar die Änderungen am DataGrid jedoch geht das Binding für ein weiteres bearbeiten komplett verloren.
Hat jemand eine Idee oder einen Tip für mein Vorhaben?

Danke



private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 3951

beantworten | zitieren | melden

Hallo und willkommen,

warum arbeitest du nicht mit [Artikel] MVVM und DataBinding?

Dann würdest du im ViewModel direkt eine Eigenschaft vom Typ ObservableCollection<Mitarbeiter> halten und nach Änderung des einen Eintrags PropertyChanged(...) aufrufen (dazu muß jedoch auch die Klasse Mitarbeiter das Interface INotfiyPropertyChanged implementieren, evtl. brauchst du dazu dann eine ViewModel-spezifische Mitarbeiter-Klasse).
private Nachricht | Beiträge des Benutzers
ChristianAT
myCSharp.de - Member



Dabei seit:
Beiträge: 2

Themenstarter:

beantworten | zitieren | melden

Danke für den Link und deine Hilfe.
Aber auch wenn MVVM eingehalten wird habe ich doch das selbe Problem, oder verstehe ich da was falsch?
Ich habe ein kleines MVVM beispiel aufgebaut, jedoch mit dem selben Ergebnis:

XAML:

	<DataGrid ColumnWidth="auto" 
			AutoGenerateColumns="False" 
			IsReadOnly="False" 
			CanUserAddRows="True" 
			CanUserDeleteRows="True" 
			SelectionMode="Single" 
			RowDetailsVisibilityMode="Collapsed" 
			CellStyle="{StaticResource DataGridRowVerticalCenter}" 
			ItemsSource="{Binding Path=Mitarbeiter}"
			SelectedItem="{Binding Path=SelectedMitarbeiter}"
			RowEditEnding="DataGrid_RowEditEnding">
  .............

code behind:


public partial class MitarbeiterPage : Page
	{
		public MitarbeiterPage()
		{
			InitializeComponent();
			this.DataContext = new MitarbeiterViewModel();
		}

		private void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
		{
			(this.DataContext as MitarbeiterViewModel).Update();
		}
}

Da RowEditEnding nicht an ein Command gebunden werden kann, rufe ich im Event die Update Methode vom ViewModel auf.

ViewModel:



public class MitarbeiterViewModel : BaseViewModel
	{
		WCFManagerServiceClient _wcfService;
		public MitarbeiterViewModel()
		{
			_wcfService = new WCFManagerServiceClient();
            UpdateCommand = new RelayCommand(Update);
			LoadData();
		}

		private ObservableCollection<Mitarbeiter> _mitarbeiter;
		public ObservableCollection<Mitarbeiter> Mitarbeiter 
		{
			get { return _mitarbeiter; }
			set 
			{
				_mitarbeiter = value;
				OnPropertyChanged("Mitarbeiter");
			}
		}
		private void LoadData()
		{
			Mitarbeiter = new ObservableCollection<Mitarbeiter>(_wcfService.MitarbeiterGet());
		}

		private Mitarbeiter _selectedMitarbeiter;
		public Mitarbeiter SelectedMitarbeiter 
		{
			get { return _selectedMitarbeiter; }
			set 
			{
				_selectedMitarbeiter = value; 
				OnPropertyChanged("SelectedMitarbeiter"); 
			}
		}

		#region Commands
		public RelayCommand UpdateCommand { get; }

		public void Update()
		{
			try 
			{
				_wcfService.MitarbeiterUpdate(SelectedMitarbeiter);
				LoadData();
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}
		#endregion
	}	


Wenn ich nach dem Update mit LoadData() die Daten aktualisiere, weil der WCF Service einige Daten ergänzt hat, ist das gesamte DataGrid zurückgesetzt.
Sprich kein Focus, Sortierung, RowDetails nicht mehr expanded etc.
Auch wenn ich nur das Objekt in der Property Mitarbeiter aktualsiere verhälts sich das DataGrid "unschön".
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 122
Herkunft: Münster

beantworten | zitieren | melden

Zu den Methodenaufruf


OnPropertyChanged()
würde ich keine magic strings nehmen, sondern


nameof(PropertyName)

private Nachricht | Beiträge des Benutzers
JimStark
myCSharp.de - Member

Avatar #dOpLzh7hN1az1g0eGRc0.jpg


Dabei seit:
Beiträge: 213

beantworten | zitieren | melden

Zitat von ChristianAT
Wenn ich nach dem Update mit LoadData() die Daten aktualisiere, weil der WCF Service einige Daten ergänzt hat, ist das gesamte DataGrid zurückgesetzt.
Sprich kein Focus, Sortierung, RowDetails nicht mehr expanded etc.
Auch wenn ich nur das Objekt in der Property Mitarbeiter aktualsiere verhälts sich das DataGrid "unschön".

Mit der Model-Liste, die du vom WCF Service bekommst, aktualisierst du einfach die ViewModel-Liste (ein ViewModel des Models, nicht wie du es gemacht hast). So könntest du prüfen ob sich an einzelnen Items was verändert hat, und wenn ja, dann aktualisieren.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von JimStark am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15528
Herkunft: BW

beantworten | zitieren | melden


_wcfService.MitarbeiterUpdate(SelectedMitarbeiter);

Damit übergibst Du UI-Logik an eine Service-Klasse.
Das ist prinzipiell genau anders rum, wie man es tun sollte.

Der Service sollte eine Liste zurück geben, die Du in der UI bindest.

Im Endeffekt kann man das zusammen mit Reactive Extensions noch weiter perfektionieren; aber denke, dass Du das erst angehen solltest, wenn Du MVVM verstanden hast.
https://oz-code.com/blog/net-c-tips/reactive-wpf-part-1-introduction-to-reactive-extensions
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 3951

beantworten | zitieren | melden

@ChristianAT. Du hast meinen eingeklammerten Satz noch nicht beachtet. Nimm dir ein Beispiel an dem Code in C# WPF & MVVM | update data of a property with a binding to the object (bei dir dann die Klasse Mitarbeiter statt Student).
Und statt dem Neuladen aller Daten, einfach die passenden Eigenschaften des Mitarbeiter-Objekts ändern (und dieses ruft dann PropertyChanged auf!).

Wie auch JimStark geschrieben hat, wenn Mitarbeiter bei dir bisher eine reine Modelklasse ist, dann erzeuge eine weitere ViewModel-spezifische Klasse und verwende diese dann (d.h. kopiere die Daten aus dem Model in das VM-Datenobjekt).

PS: Auch die Verwendung von [CallerMemberName] beim OnPropertyChanged-Aufruf vereinfacht den Code.
private Nachricht | Beiträge des Benutzers