Hallo zusammen,
ich hab folgendes Problem :
ich versuche gerade eine ObservableCollection an ein RadGridView (Telerik) zu binden.
Wenn ich das SelectedItem ebenfalls an mein MVVM binde und dort Änderungen tätige, werden diese zwar in die Datenquelle übernommen, allerdings aktualisiert sich mein RadGridView nicht?
Kann mir jemand vielleicht helfen wo mein Fehler aktuell ist :
ViewModel
public System.Collections.ObjectModel.ObservableCollection<View_Extraroehrchen> Extraröhrchen { get { return _Extraröhrchen; } set { _Extraröhrchen = value; OnPropertyChanged("Extraröhrchen"); } }
protected virtual void OnPropertyChanged(string PropertyName)
{
PropertyChanged.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(PropertyName));
}
WPF
<telerik:RadGridView AutoGenerateColumns="False"
IsFilteringAllowed="False" ShowGroupPanel="False"
RowIndicatorVisibility="Collapsed"
telerik:StyleManager.Theme="Windows8Touch"
ItemsSource="{Binding Extraröhrchen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Extraröhrchen_SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<telerik:GridViewDataColumn DataMemberBinding="{Binding AUSGELAGERT_DATUM, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Header="Datum"
HeaderTextAlignment="Center"
MinWidth="80">
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding AUSGELAGERT_DATUM, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
<telerik:GridViewDataColumn.CellEditTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<telerik:RadDatePicker Margin="3"
SelectedValue="{Binding DataContext.Extraröhrchen_Datum, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource AncestorType=telerik:RadGridView}}"/>
</Grid>
</DataTemplate>
</telerik:GridViewDataColumn.CellEditTemplate>
</telerik:GridViewDataColumn>
</telerik:RadGridView
Wie ich aktuell versuche das ganze zu ändern im Code :
if (ViewModel.Extraröhrchen_Auslagern == true)
{
// --- Datum --- //
ViewModel.Extraröhrchen_Datum = DateTime.Now;
ViewModel.Extraröhrchen_SelectedItem.AUSGELAGERT_DATUM = DateTime.Now;
//ViewModel.Extraröhrchen.Find(x => x.Praeparat_ID == ViewModel.Extraröhrchen_SelectedItem.Praeparat_ID).AUSGELAGERT_DATUM = DateTime.Now;
}
Die Daten werden offensichtlich korrekt übernommen, allerdings wird im RadGridView die Änderung erst angezeigt sobald ich in das Feld klicke und wieder ein anderes auswähle.
Grüße
View_Extraroehrchen muss INotifyPropertyChanged implementieren.
Das spielt doch keine Rolle. Wenn du Entites direkt an GUI-Elemente bindest müssen diese ebenfalls die GUI benachrichtigen wenn sich Properties ändern damit die GUI sich aktualiseren kann.
Aber wo soll ich das denn dort einfügen? Die Klasse von wo das Objekt kommt erbt bereits vom DBContext
Vielleicht kannst du mir mit einem Beispiel weiterhelfen?
Was ist denn View_Extraroehrchen? Wie ist das definiert?
Ein Objekt aus der Datenbank.
public virtual DbSet<View_Extraroehrchen> View_Extraroehrchens { get; set; }
Dann bau ein Objekt ( ViewModel ) welches du stattdessen in deinem RadGridView darstellst. Entities sind nicht dazu gedacht diese direkt in der UI anzuzeigen. Im Zweifelsfall wrap deine Entities zumindest in deinen ViewModels
Hab ich doch? Ich hab ein ViewModel mit einer ObservableCollection die vom Typ View_Extraroehrchen ist, dieser Typ stammt aus der EntitiyFramework Klasse der dort definitiert ist.
Hat denn in dem Zusammenhang überhaupt schon mal jemand Erfahrung gesammelt? Scheint irgendwie nicht so.
Grüße
Du sollst View_Extraroehrchen
in einer eigene (ViewModel-)Klasse wrappen (welche dann INotifyPropertyChanged
implementiert). DB-Objekte (Entities) sollten niemals direkt an die GUI gebunden werden, s.a. [Artikel] Drei-Schichten-Architektur.
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.Test.Rebind();
}
), System.Windows.Threading.DispatcherPriority.ApplicationIdle, null);
Immerhin mal etwas was funktioniert ..
Was du da machst ist halt keine Lösung deines eigentlichen Problems sondern ein kostenintensiver workaround.
Was wir meinen ist z.B. folgendes:
public class MyViewModelForGrid : INotifyPropertyChanged
{
public MyViewModelForGrid( MyEntity entityToWrap )
{
this._entityToWrap = entityToWrap;
}
public string MyProperty
{
get { return _entityToWrap.Property; }
set
{
this._entityToWrap.Property = value;
this.RaisePropertyChanged();
}
}
}
Ist jetzt nur schnell im Editor zusammengeschrieben und daher unvollständig. Aber die Idee ist hoffentlich ersichtlich.
Naja mit den aktuellen Vorschlägen kam ich noch nicht wirklich weiter und irgendwie muss ich ja voran kommen ..
Und in was oder wie konvertiere ich ein DBSet?
Bist du dir überhaupt sicher dass das RadGridView dann auch die Änderungen bemerkt? Oder vermutest du das ganze einfach nur?
Wir tippen nur wahllos auf der Tastatur rum und tragen den ganzen Tag einen Aluhut. 🤔
Wirkt auch so 8o
Wenn mich jemand das nächste mal fragt warum sein Auto nicht funktioniert, sag ich ihm auch einfach reparier es 👍 Sollte ja auf anhieb wissen wie er es umzusetzen hat. :rtfm:
Und in was oder wie konvertiere ich ein DBSet?
Das machst du doch schon. In deinem Code oben scheinst du ja eine ObservableCollection zu verwenden. D.h. nach dem Holen von Daten bist du ja gar nicht mehr von deinem DBSet abhängig.
Statt halt einfach die Entities in die Collection zu packen wrapst du sie halt vorher in einem ViewModel.
Technisch bemerkt dein RadGridView eigentlich nichts sondern die WPF Engine sorgt bei dafür, dass Objekte die INotifyPropertyChanged implementieren, auch in der UI aktualisiert werden wenn das Binding stimmt.
Anhand deines Snippets sieht man halt recht wenig was du vor hast und wie bestimmte Dinge bei dir momentan umgesetzt sind. z.b. hab ich keine Ahnung wie du momentan überhaupt Daten bis zu deiner UI bringst.
Sprich: Ja wir müssen hier sehr viel Vermuten weil wir nicht an deinem Projekt beteiligt sind und nicht in deinen Kopf schauen können 😃. Viele Probleme du grade hast hatten wir auch schon 100x und haben gewisse Standardlösungen parat. Dir sollte aber klar sein, dass wir hier nur gewisse Lösungsansätze geben können und du es ansonsten schon selbst schaffen musst die Ansätze in die Tat umzusetzen.
Statt halt einfach die Entities in die Collection zu packen wrapst du sie halt vorher in einem ViewModel.
Also ich packe meine Entities in ein extra ViewModel und befülle meine ObservableCollection dann mit dem ViewModel oder wie?
Anhand deines Snippets sieht man halt recht wenig was du vor hast und wie bestimmte Dinge bei dir momentan umgesetzt sind. z.b. hab ich keine Ahnung wie du momentan überhaupt Daten bis zu deiner UI bringst.
Aber das ist doch eine Aussage mit der ich arbeiten kann.
mein aktuelles ViewModel :
public System.Collections.ObjectModel.ObservableCollection<View_Extraroehrchen> Extraröhrchen { get { return _Extraröhrchen; } set { _Extraröhrchen = value; OnPropertyChanged("Extraröhrchen"); } }
protected virtual void OnPropertyChanged(string PropertyName)
{
PropertyChanged.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(PropertyName));
}
meine Klasse :
this.DataContext = ViewModel;
ViewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(OnPropertyChanged);
set_Default_Values();
Befüllung der Daten
ViewModel.Extraröhrchen = Vita34.Data.VitaLab.VitaLab3.Liste.Liste.Get.GetViewExtraroehrchen(
ViewModel.Extraröhrchen_Filterbereich_Tagesliste_Datum,
ViewModel.Extraröhrchen_Filterbereich_Tagesliste_Datum.AddDays(1)
);
Anbindung an die Oberfläche
<telerik:RadGridView AutoGenerateColumns="False"
IsFilteringAllowed="False" ShowGroupPanel="False"
RowIndicatorVisibility="Collapsed"
telerik:StyleManager.Theme="Windows8Touch"
ItemsSource="{Binding Extraröhrchen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Extraröhrchen_SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Bearbeitung der Daten
if (ViewModel.IsWorking == false)
{
if (ViewModel.Extraröhrchen_SelectedItem != null)
{
ViewModel.Extraröhrchen_SelectedItem.AUSGELAGERT_VON = ViewModel.Extraröhrchen_Bearbeiter;
}
}
Die Antwort von KroaX ("class MyViewModelForGrid") gilt immer noch.
Du wärst schon lange fertig, wenn du es nicht dauernd hinterfragen würdest Warum eigentlich? Verstehst du die Grundlagen des DataBindings (PropertyChanged) nicht?
Versuch dich ein bisschen in unsere Lage zu versetzen wenn du eine Frage stellst 😃
Vita34.Data.VitaLab.VitaLab3.Liste.Liste.Get.GetViewExtraroehrchen(...)
Wir können nicht verstehen was da passiert. Offensichtlich kommt da eine ObservableCollection zurück. Aber was in dieser Methode passiert und wie deine Entities in diese ObservableCollection gelangen sehen wir nicht. Dort ist aber scheinbar ein möglicher Platz für dein Wrapping.
Also ich packe meine Entities in ein extra ViewModel und befülle meine ObservableCollection dann mit dem ViewModel oder wie?
Jede deiner Entities ist ein eigenes ViewModel. Und ja deine ObservableColleciton ist dann eine Auflistung dieser ViewModels.
Mir scheint auch, dass dir sehr viele Grundlagen zu WPF, XAML und Databinding fehlen. Niemand setzt voraus, dass du das schon alles weißt wenn du hier eine Frage stellst aber zu sehr vielen Dingen ( grade zu Grundlagen ) findet man mit Google auch selbst schnell eine Antwort.
https://wpftution.blogspot.com/2012/05/mvvm-sample-using-datagrid-control-in.html
Wir können nicht verstehen was da passiert. Offensichtlich kommt da eine ObservableCollection zurück. Aber was in dieser Methode passiert und wie deine Entities in diese ObservableCollection gelangen sehen wir nicht. Dort ist aber scheinbar ein möglicher Platz für dein Wrapping.
using (VitaLab3Entities VitaLab = new VitaLab3Entities())
{
var Extraröhrchen = VitaLab.View_Extraroehrchens.Where(x => x.ANNAHME_DATUM > AnnahmeDatum && x.ANNAHME_DATUM < AnnahmeDatumBis).OrderBy(x => x.ANNAHME_DATUM);
return new System.Collections.ObjectModel.ObservableCollection<View_Extraroehrchen>(Extraröhrchen);
}
Wäre schon gut wenn du es selbst löst.
https://stackoverflow.com/questions/9881790/how-to-design-viewmodel
Das sind echt absolute Basics der Programmierung zu verstehen was ein Wrapper ist oder wie man LINQ verwendet wenn man es verwenden möchte. Einfach drauf los programmieren funktioniert bis zu einem gewissen Grad aber irgendwann muss man doch etwas mehr darüber lesen und verstehen was man da eigentlich macht.
Mehr kann ich dir da jetzt auch nicht an die Hand geben. In dem Link ist in ähnlicher Weise erklärt was du tun müsstest.
Hier geht es wirklich um die grundlegenden Dinge im Umgang mit WPF. Die sind hier erklärt: [Artikel] MVVM und DataBinding
Weeks of programming can save you hours of planning
So war es wohl auch nicht gemeint .. 🙁
Datenquelle
public static List<View_Extraroehrchen> return_Extraröhrchen()
{
try
{
using (VitaLab3Entities VitaLab = new VitaLab3Entities())
{
var x = VitaLab.View_Extraroehrchens.ToList();
return x;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace.ToString());
}
return null;
}
ViewModel
private ObservableCollection<ViewModel_Extraröhrchen_Test> _Test;
public ObservableCollection<ViewModel_Extraröhrchen_Test> Test { get { return _Test;} set { _Test = value; OnPropertyChanged("Test"); } }
public class ViewModel_Extraröhrchen_Test
{
public string Format_Praeparat_ID { get; set; }
public DateTime? AUSGELAGERT_DATUM { get; set; }
}
Window
ViewModel.Test = new System.Collections.ObjectModel.ObservableCollection<Vita34.VitaLab.Windows.VitaLab.ViewModel.ViewModel_Extraröhrchen_Test>(Vita34.Data.VitaLab.VitaLab3.Sammellisten.Extraröhrchen.Extraröhrchen.Get.return_Extraröhrchen().Select(x => new VitaLab.ViewModel.ViewModel_Extraröhrchen_Test
{
Format_Praeparat_ID = x.Format_Praeparat_ID,
AUSGELAGERT_DATUM = x.AUSGELAGERT_DATUM
}
));
Wenn Du schon Deutsch programmierst, was an für sich schon schlimm genug ist, lass doch wenigstens die Umlaute weg... 👍
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Er zeigt mir jetzt zwar schön meine Änderungen im RadGridView an, allerdings wenn ich vom Code aus etwas im ViewModel setze wird irgendwie kein PropertyChanged Event ausgelöst, er springt irgendwie gar nicht erst in den Set Bereich ..
ViewModel Extraröhrchen
private ObservableCollection<ViewModel_Extraröhrchen_RadGridView> _Extraröhrchen_RadGridView;
private ViewModel_Extraröhrchen_RadGridView _Extraröhrchen_RadGridView_SelectedItem;
public ObservableCollection<ViewModel_Extraröhrchen_RadGridView> Extraröhrchen_RadGridView { get { return _Extraröhrchen_RadGridView; } set { _Extraröhrchen_RadGridView = value; OnPropertyChanged("Extraröhrchen_RadGridView"); } }
public ViewModel_Extraröhrchen_RadGridView Extraröhrchen_RadGridView_SelectedItem { get { return _Extraröhrchen_RadGridView_SelectedItem; } set { _Extraröhrchen_RadGridView_SelectedItem = value; OnPropertyChanged("Extraröhrchen_RadGridView_SelectedItem"); } }
ViewModel_Extraröhrchen_RadGridView
public List<Vita34.Data.VitaLab.Database.TNK_TANK> Extraröhrchen_RadGridView_TANK { get { return _Extraröhrchen_RadGridView_TANK; } set {_Extraröhrchen_RadGridView_TANK = value; } }
public int Extraröhrchen_RadGridView_TANK_SelectedIndex { get { return _Extraröhrchen_RadGridView_TANK_SelectedIndex; } set { _Extraröhrchen_RadGridView_TANK_SelectedIndex = value; OnPropertyChanged("Extraröhrchen_RadGridView_TANK_SelectedIndex"); } }
public string Extraröhrchen_RadGridView_TANK_NAME { get { return _Extraröhrchen_RadGridView_TANK_NAME; } set { _Extraröhrchen_RadGridView_TANK_NAME = value; OnPropertyChanged("Extraröhrchen_RadGridView_TANK_NAME"); } }
Window
ViewModel.Extraröhrchen_RadGridView_SelectedItem.Extraröhrchen_RadGridView_TANK = Vita34.Data.VitaLab.Helper.Get.DropDownTanks("E");
XAML
<telerik:GridViewDataColumn.CellEditTemplate>
<DataTemplate>
<ComboBox Margin="3"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
ItemsSource="{Binding Extraröhrchen_RadGridView_TANK}"
DisplayMemberPath="TANK_NAME"
SelectedIndex="{Binding Extraröhrchen_RadGridView_SelectedItem.Extraröhrchen_RadGridView_TANK_SelectedIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</telerik:GridViewDataColumn.CellEditTemplate>
Liegt es daran das ich im SelectedItem die Werte befülle und er dann irgendwie den Bezug verliert? Seltsamerweise lässt sich vom Code aus die Datenquelle befüllen, was er auch richtig anzeigt.
Oder bring ich da wieder etwas durcheinander?
Brauch das neue ViewModel auch nochmal ein INotifyPropertyChanged?
Edit : Jup, dachte es reicht wenn es vom ersten erbt.
Wenn das ViewModel, von dem du erbst, bereits INotifyPropertyChanged implementiert, dann braucht das andere ViewModel es nicht mehr implementieren.
Evtl. solltest du dir die Grundlagen nochmal in einem minimalen Testprojekt anschauen.
Ich zumindest bin bei deinen ganzen ViewModel_Extraröhrchen_RadGridView_View_View_Model_PiPaPo ausgestiegen... 😉
wenn ich vom Code aus etwas im ViewModel setze wird irgendwie kein PropertyChanged Event ausgelöst, er springt irgendwie gar nicht erst in den Set Bereich
Vom Code aus wo? Deine Formulierung ist hier nicht genau genug.
Bitte gib keine Antwort bis du nicht auf jede der Fragen eine Antwort hast.
Ging leider nicht, obwohl es im anderen bereits implementiert war. 👶
Dann liegt was anderes im Argen.