Benutzer mit den meisten Antworten
MVVM Cast ViewModel

Frage
-
Hallo zusammen,
in meiner Anwendung habe ich mich dazu entschlossen mit Tabs zu arbeiten welche einen Close-Button im Header eingebunden haben das ganze von CodeProject CloseTabItem. Soweit sogut!
In den DataContext lade ich nun ein Usercontrol und weise dem Control ein ViewModel zu:
CloseableTab ct = new CloseableTab("STATIONEN"); if (Tabs.Where(r => ((CloseableTab)r).Title == ct.Title).Count() == 0) { Usercontrols.Stationen stationen = new Usercontrols.Stationen(); stationen.DataContext = new StationenViewModel(); ct.Content = stationen; ct.CloseTab += TabSchliessen_Execute; Tabs.Add(ct); }
Jetzt möchte ich aber von meiner Hauptanwendung auf das UserControl bzw. das jeweilige ViewModel zugreifen. Muss man dazu den kompletten Visualtree durch-Casten um das ViewModel zu erreichen oder gibt es da eine elegantere Lösung?
private void StationenSpeichern_Execute(object obj) { var stationsTab = Tabs.Where(r => r.IsSelected && ((CloseableTab)r).Title == "STATIONEN").FirstOrDefault(); if (stationsTab != null) { StationenViewModel stationen = ((CloseableTab)stationsTab).DataContext as StationenViewModel; if (stationen != null) { stationen.StationenSpeichern_Execute(obj); } } }
Antworten
-
Ich habe nun folgende Lösung:
1. Interface für ViewModels generieren. Die GUID wird später zur Identifikation herangezogen
public interface IViewModel { string GUID { get; } }
2. ViewModels mit dem Interface aufbauen
public class AnlageViewModel : ModelBase.ModelBase, Interface.IViewModel { private string guid; public string GUID { get { return guid; } } public AnlageViewModel() { guid = Guid.NewGuid().ToString(); } }
3. Im MainViewModel dann zwei Listen anlegen
public ObservableCollection<CloseableTab> Tabs { get { return tabs; } set { tabs = value; OnChanged(); } } public List<KeyValuePair<string, Interface.IViewModel>> ViewModels { get; set; }
4. Über eine generische Methode kann ich nun die Tabs mit den ViewModels anlegen und über die GUID identifizieren.
private void Tab_Anlegen<V, U>(V viewModel, U usercontrol, string Title, int AnzahlTabs = 1) { // Absprung wenn Anzahl erreicht if (Tabs.Where(r => r.Title.ToUpper() == Title.ToUpper()).Count() >= AnzahlTabs) { return; } CloseableTab ct = new CloseableTab(); ct.GUID = ((Interface.IViewModel)viewModel).GUID; ct.Title = Title; ct.Content = usercontrol; ct.DataContext = viewModel; ct.CloseTab += TabSchliessen_Execute; Tabs.Add(ct); ViewModels.Add(new KeyValuePair<string, Interface.IViewModel>(((Interface.IViewModel)viewModel).GUID, ((Interface.IViewModel)viewModel))); }
Ich weiß nicht ob das jemanden weiterbringt, aber ich bin zufrieden :-) Optimierungen sind selbstverständlich erwünscht!
- Als Antwort markiert Aleksander Chalabashiev Mittwoch, 4. November 2015 09:29
Alle Antworten
-
Hallo David,
sobald du irgendwie von C# aus auf den Visual- oder den LogicalTree zugreifst ist das MVVM Pattern eigentlich schon verletzt. Du musst also alles irgendwie im ViewModel selbst abhandeln.
Wenn ich das richtig sehe hat jeder Tab ein StationenViewModel als DataContext. Wenn du nun eine Methode eines solchen VMs aufrufen möchtest musst du die Liste aller StationenViewModels in deinem MainViewModel durchgehen und das entsprechende VM heraus suchen. Wichtig hier für ist, dass die Liste der Tab-ViewModels auch im MainViewModel vorhanden sind.
Tom Lambert - .NET (C#) MVP
Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets -
Hallo Koopakiller,
danke für deine Antwort! Ich versuche das mal wie folgt umzusetzen:
Mit der Klasse TabItemInformation erstelle ich das CloseableTab UND den DataContext mit dem ViewModel sowie einen Title.
public class TabItemInformation : ModelBase.ModelBase { #region Fields private CloseableTab tabitem; private object datacontext; private string title; #endregion public CloseableTab TabItem { get { return tabitem; } set { tabitem = value; OnChanged(); } } public object DataContext { get { return datacontext; } set { datacontext = value; OnChanged(); } } public string Title { get { return title; } set { title = value; OnChanged(); } } public TabItemInformation(object Content, object DataContext, string Title) { this.TabItem = new CloseableTab(); this.DataContext = DataContext; this.TabItem.DataContext = DataContext; this.TabItem.Content = Content; this.Title = Title; this.TabItem.Title = Title; } }
In meinem MainViewModel habe ich eine ObservableCollection von TabItemInformation:
public ObservableCollection<Model.TabItemInformation> Tabs { get { return tabs; } set { tabs = value; OnChanged(); } }
Was muss ich im XAML nun vorgeben, damit aus der ObservableCollection Tabs, das TabItem Element verwendet wird zum Aufbau des TabControls?
<TabControl ItemsSource="{Binding Tabs}" > ... </TabControl>
-
Ich habe nun folgende Lösung:
1. Interface für ViewModels generieren. Die GUID wird später zur Identifikation herangezogen
public interface IViewModel { string GUID { get; } }
2. ViewModels mit dem Interface aufbauen
public class AnlageViewModel : ModelBase.ModelBase, Interface.IViewModel { private string guid; public string GUID { get { return guid; } } public AnlageViewModel() { guid = Guid.NewGuid().ToString(); } }
3. Im MainViewModel dann zwei Listen anlegen
public ObservableCollection<CloseableTab> Tabs { get { return tabs; } set { tabs = value; OnChanged(); } } public List<KeyValuePair<string, Interface.IViewModel>> ViewModels { get; set; }
4. Über eine generische Methode kann ich nun die Tabs mit den ViewModels anlegen und über die GUID identifizieren.
private void Tab_Anlegen<V, U>(V viewModel, U usercontrol, string Title, int AnzahlTabs = 1) { // Absprung wenn Anzahl erreicht if (Tabs.Where(r => r.Title.ToUpper() == Title.ToUpper()).Count() >= AnzahlTabs) { return; } CloseableTab ct = new CloseableTab(); ct.GUID = ((Interface.IViewModel)viewModel).GUID; ct.Title = Title; ct.Content = usercontrol; ct.DataContext = viewModel; ct.CloseTab += TabSchliessen_Execute; Tabs.Add(ct); ViewModels.Add(new KeyValuePair<string, Interface.IViewModel>(((Interface.IViewModel)viewModel).GUID, ((Interface.IViewModel)viewModel))); }
Ich weiß nicht ob das jemanden weiterbringt, aber ich bin zufrieden :-) Optimierungen sind selbstverständlich erwünscht!
- Als Antwort markiert Aleksander Chalabashiev Mittwoch, 4. November 2015 09:29