ich versuche gerade eine Applikation zu bauen, in der aus einer ObservableCollection von Models dynamisch per ItemsContol template die zugehörigen ViewModels geladen werden. Das binding der Daten aus den Objekten der ObservableCollection zum XAML funktioniert soweit, die richtigen Einträge werden dargestellt. Was mir jedoch nicht gelingt ist das Ausführen von Methoden auf dem Objekt des zugehörigen ViewModels, bspw. wenn man einen Button in einem VM klickt.
Ich hoffe ich konnte mein Problem ausreichend beschreiben sowie, dass jemand mir helfen kann, per google/Forensuche hatte ich keinen Erfolg - vielleicht sind es auch die falschen Begriffe
Mein Ziel ist, eine Liste von ViewModels in meiner MainView in einem Dock zu erzeugen, die physischen Netzwerkgeräten folgt. Jedes Gerät soll dynamisch sein ViewModel bekommen, das ViewModel soll in der Lage sein, Funktionen auf dem betreffenden Viewmodel für ein Gerät auszuführen. Um die Eigenschaften eines Gerätes zu organisieren habe ich ein Model erstellt, mit Eigenschaften wie IP, Verbindung, etc.
In meinem MainViewModel baue ich dann die ObservableCollection<Gerät> Geräte und binde dann in das XAML die Collection wie folgt:
<Grid>
<avalonDock:DockingManager Name="dockingManager" Loaded="OnDockManagerLoaded">
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal" CanRepositionItems="False">
<avalonDock:LayoutAnchorablePane DockMinWidth="500"
DockWidth="500"
CanRepositionItems="False" >
<avalonDock:LayoutAnchorable x:Name="dockGeräte"
Title="Geräte"
AutoHideMinHeight="500"
AutoHideMinWidth="495"
CanClose="False"
CanDockAsTabbedDocument="False"
CanFloat="False"
CanHide="False">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ItemsControl ItemsSource="{Binding Geräte}" Width="460">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:Gerät Margin="5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</avalonDock:LayoutAnchorable>
</avalonDock:LayoutAnchorablePane>
<avalonDock:LayoutDocumentPane ShowHeader="False">
<avalonDock:LayoutDocument CanClose="False"
CanFloat="False"
IsMaximized="True">
<!-- Hier kommen dann weitere (auswählbare) control-ViewModels für die Geräte rein, welche aus dem Ribbon für ein ausgewähltes Gerät bestimmte Funktionen ausführen (bspw. Kommunikation aneigen) -->
</avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane>
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>
</Grid>
Gebundene Funktionen auf die ViewModels der Geräte funktionieren, ich kann jedoch nicht die Eigenschaften des Models abrufen, dessen Button auf dem ViewModel geklickt wurde.
Ich hoffe, das war etwas verständlicher, vielen Dank schon mal für Eure Antworten.
ich kann jedoch nicht die Eigenschaften des Models abrufen, dessen Button auf dem ViewModel geklickt wurde.
Das musst du näher ausführen. Was ist dein Model ( Gerät? ). Wie willst du die Eigenschaften abrufen?
EIn Button wird nicht auf einem ViewModel geklickt. Du hast vielleicht einen Command in deinem ViewModel welcher per Binding auf einen Button in deinem DataTemplate gebunden ist.
Dein DataTemplate besteht hier jedoch nur aus einem Gerät Control. Das Control müsste man mal sehen.
Ich hoffe der Typ Gerät aus ObservableCollection<Gerät> entspricht nicht demselben Typ Gerät deines Controls ( local:Gerät ) ansonsten hast du etwas missverstanden bei MVVM Konzept.
Mein Model Gerät ist eine Klasse, die von der Klasse ModelBase (ich verwende catel) erbt. Da hab ich Eigenschaften des Gerätes drin, bspw.
public class Gerät : ModelBase
{
#region Properties
/// <summary>
/// IP-Address of the device
/// </summary>
public IPAddress IP
{
get { return GetValue<IPAddress>(IPProperty); }
set { SetValue(IPProperty, value); }
}
public static readonly PropertyData IPProperty = RegisterProperty(nameof(IP), typeof(IPAddress), null);
Der Typ aus der ObservableCollection<Gerät> ist das Model, also ObservableCollection<Models.Gerät>, das Control das in dem DataTemplate steckt ist ein Viewmodel mit ebenfalls dem Namen "Gerät". Dort hab ich Commands die im ViewModel Gerät drin stehen und bei Tastendruck ausgeführt werden. Ich verstehe nur nicht, wie ich jetzt Daten aus dem Model in das Viewmodel bekomme. Wo ist mein Denkfehler?
Was ich eigentlich wollte:
Eine ObservableCollection die ich schön speichern kann, organisiert in den Models (das sollte doch eigentlich richtig so sein) und ein ViewModel, welches sich an den Objekten in der Collection bedient und die Eigenschaften darstellt.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von torka am .
Wenn Du schon unbedingt in Deutsch Quellcode schreibst, was ohnehin nicht schön ist, lass wenigstens die Umlaute weg.
Umlaute werden prinzipiell unterstützt (in C#) - machen trotzdem an einigen Stellen hin und wieder Probleme.
das Control das in dem DataTemplate steckt ist ein Viewmodel
Ein Control ist niemals ein ViewModel, sondern eine View.
Das Objekt, das Du per Binding mit dieser View verbindest, ist ein ViewModel - also das, was Du hier als Model bezeichnest.
Schau Dir nochmal ein paar Artikel zu MVVM an, z.B. [Artikel] MVVM und DataBinding , hier liegt offenbar noch ein grundsätzliches Verständnisproblem vor.
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
Ja, es ist ein View. Das ViewModel heißt DeviceViewModel, die View' Device' (vorher Gerät). Aber ist denn mein Ansatz mit der ObservableCollection richtig?
public class DeviceViewModel : ViewModelBase
{
#region Public Properties
/// <summary>
/// device serial number
/// </summary>
public String SerialNumber { get; set; }
/// <summary>
/// device IP
/// </summary>
public String IP { get; set; }
#endregion
#region Commands
/// <summary>
/// Remove device
/// </summary>
public ICommand RemoveDevice { get; set; }
#endregion
#region Constructor
public DeviceViewModel()
{
RemoveDevice = new TaskCommand(RemoveDevice);
}
private async Task RemoveDevice)
{
System.Windows.Forms.MessageBox.Show("RemoveDevice aufgerufen");
}
}
Der RemoveDevice command wird aufgerufen, das binding funktioniert in dieser Richtung. Was mir (und meinem Verständnis noch) fehlt ist das Binding auf die Eigenschaften aus der ObesservableCollection, die im MainViewModel steckt. Es ist auf jeden Fall schon mal so, dass mir in meiner ItemsControl zwei Device-Views angezeigt werden, wenn die OC auch zwei Einträge hat. Was schief läuft ist wohl das binding. Bin ich da auf nem Holzweg?
Die Antwort hat dir doch MarsStein schon im ersten Post gegeben. Und wenn das nicht verständlich ist, schau mal in den Artikel, der dir verlinkt wurde. Da gibt es Beispiel-Code und ein Beispiel-Projekt.
Weeks of programming can save you hours of planning
Warum möchtest du in der ObservableCollection denn unbedingt Models haben?
Wäre es nicht logischer deine DeviceViewModels in dieser Collection zu halten und jedes DeviceViewModel ist der Container für ein Model? Damit sollte dein Problem der Hierarchie doch einfach lösbar sein?
Meine Idee war, dass ich dann bei Programmstart und -ende die Devices besser als XML mit einem XMLSerializer laden bzw. speichern kann. Ist das ein sinnvolles Konzept?
Ich bin relativ unerfahren in der Richtung, hatte bisher nur schnell mal die ein oder andere C#-Applikation zusammengetippt, das hier ist mein erstes MVVM-Konzept.
Du siehst doch selbst, daß es nicht funktioniert :)
Daher, nein. Die ViewModels haben eine Funktion, und die Models haben eine andere Funktion, und der Sinn der Schichtentrennung ist es, diese beiden Verantwortlichkeiten voneinander zu entkoppeln. Verwende daher in der View die ViewModels, um die Daten anzuzeigen und zu bearbeiten, und die Models beim Datenzugriff, um sie zu laden und zu speichern.