I've been struggling with the MVVM concept a lot. I am developing a remote file browser, so I can manage files on another computer from my own. I have a button that will open a new tab, so you can have multiple tab views of the files. When a new tab is opened, it should send a request to the client to get a list of drives, which will then be displayed in the newly created tab.

The way I am currently doing this is almost certainly not correct MVVM. I am using a Button_Click to enqueue the item count of the SubTabControl in a global queue in my code-behind. Then, I proceed to send the command to the client to request the list of drives.

private void Button_Click(object sender, RoutedEventArgs e)
    _ems.Clients[0].Send(_ems.ModuleName, (byte)Commands.GetDrives, String.Empty);

Once I receive the command, I add each drive to the ViewModel by casting the SubTabControl to my view model with the index.

public void UpdateDrives(ModularPacket packet)
        Debug.WriteLine("Drives! Drive size is " + Marshal.SizeOf(typeof(Drive)));

        int index = _DrivesUpdateQueue.Dequeue();

        for (int i = 0; i < packet.BodyLength; i += Marshal.SizeOf(typeof(Drive)))
            Drive d = Utils.ByteArrayToStructure<Drive>(packet.Body, i);

            string x = ParseSize(d.freeSpace);



<mah:MetroWindow x:Class="FileExplorerModuleServer.FileExplorerModuleServerUI"
             mc:Ignorable="d" Title="File Explorer" Height="398.809" Width="653.198">

        <!--Set the DataContent to be an instance of our view-model class -->
        <TabControl Name = "MasterTabControl" HorizontalAlignment="Stretch" Margin="10,10,0,0" VerticalAlignment="Stretch">
            <TabItem Header="Browse Files">
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    <!--The Command of the button is bound to the View Model -->
                    <Button Grid.Row="0" HorizontalAlignment="Right" Width="100"  
                            Content="New Tab" 
                            Command="{Binding NewTabCommand}" Click="Button_Click" />

                    <!--ItemsSource is bound to the 'Tabs' property on the view-
                        model, while DisplayMemeberPath tells TabControl 
                        which property on each tab has the tab's name -->
                    <TabControl Name="SubTabControl" Grid.Row="1" 
                    ItemsSource="{Binding Tabs}" 
                    DisplayMemberPath="Header" SelectedIndex="{Binding SelectedIndex}">
                                <!--The UserControl/Grid were pointless, so I 
                                    removed them. ItemsSource of the ListView is 
                                    bound to an Items property on each object in
                                    the Tabs collection-->
                                <ListView ItemsSource="{Binding Items}">
                                            <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                                            <GridViewColumn Header="Type" DisplayMemberBinding="{Binding Type}"/>
                                            <GridViewColumn Header="Total Size" DisplayMemberBinding="{Binding TotalSize}"/>
                                            <GridViewColumn Header="Free Space" DisplayMemberBinding="{Binding FreeSpace}"/>

View Models:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace FileExplorerModuleServer
    public class MainWindowViewModel : ViewModelBase
        public int SelectedIndex
            get => _selectedIndex;
            set => Set(ref _selectedIndex, value);
        private int _selectedIndex;

        // store our list of tabs in an ObservableCollection
        // so that the UI is notified when tabs are added/removed
        public ObservableCollection<TabItemViewModel> Tabs { get; }
            = new ObservableCollection<TabItemViewModel>();

        // this code gets executed when the button is clicked
        public ICommand NewTabCommand
            => new RelayCommand(() => 
                Tabs.Add(new TabItemViewModel() { Header = $"Loading..." }); 
                SelectedIndex = Tabs.Count - 1;

    public class TabItemViewModel : ViewModelBase
        // this is the title of the tab, note that the Set() method
        // invokes PropertyChanged so the view knows if the 
        // header changes
        public string Header
            get => _header;
            set => Set(ref _header, value);
        private string _header;

        // these are the items that will be shown in the list view
        public ObservableCollection<Drive> Items { get; set; }
            = new();


Browse other questions tagged or ask your own question.