none
MVVM Cast ViewModel RRS feed

  • 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);
            }
        }
    }
    

    Montag, 26. Oktober 2015 10:57

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!

    Dienstag, 27. Oktober 2015 12:09

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

    Montag, 26. Oktober 2015 14:00
    Moderator
  • 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>

    Dienstag, 27. Oktober 2015 07:58
  • 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!

    Dienstag, 27. Oktober 2015 12:09