Search code examples
c#wpfxamlmvvm

Multiple ViewModels in MainWindowViewModel


I will probably have a stupid and many times explained question, but I did not find a simple googling answer to my question. (I'm just a beginner in C# so don't judge strictly, OOP is still a bit difficult for me to understand). I have a WPF MVVM application, inside of which I would like to implement several ViewModel for which there is one View. I want to be able to change SelectedViewModel to SelectedViewModel_One and SelectedViewModel_Two, where the same methods will be implemented inside. (as in the example).

 public  class ViewModel : INotifyPropertyChanged, IDisposable
    {
        private bool _Disposed;
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string PropertyName = null){}
        protected virtual bool Set<T>(ref T field, T value, [CallerMemberName] string PropertyName = null){}
        public void Dispose(){}
        protected virtual void Dispose(bool Disposing){}

    }


public partial class SelectedViewModel_One : ViewModel
    {
        public void Move(){}
    }

public partial class SelectedViewModel_Two : ViewModel
    {
        public void Move(){}
    }


     internal class MainWindowViewModel : ViewModel
     {
        private ViewModelAbstractBaseOrSmthLikeThat selectedViewModel = null;
        public ViewModelAbstractBaseOrSmthLikeThat SelectedViewModel
        {
             get { return selectedViewModel; }
             set { Set(ref selectedViewModel, value); }
        }
     }

     --------------
     --XAML
     --------------
<Window x:Class="SampleApplication.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        xmlns:vm="clr-namespace:SampleApplication.ViewModels"
        ResizeMode="NoResize" WindowStartupLocation="CenterScreen">

    <Window.DataContext>
        <vm:MainWindowViewModel></vm:MainWindowViewModel>
    </Window.DataContext>

    <Grid DataContext="{Binding SelectedViewModel}">
          <!--Components and binding to SelectedViewModel -->
    </Grid>

But how to properly organize the architecture of the application? What do I need to add, or change in the code of MainWindowViewModel instead of "ViewModelAbstractBaseOrSmthLikeThat"

I need to work with interfaces, and implement a base class? Or please give me a link to the simplest example how to do this, so that by changing in MainWindowViewModel - SelectedViewModel - I can call Move() methods from SelectedViewModel_One and SelectedViewModel_Two.


I have several devices which are controlled via RS232 commands. All the devices have the same functions but the commands are different. That's why there is a single View for the program


Solution

  • Here's an example of how to proceed with a base class:

    public abstract class RS232DeviceViewModel : ViewModel
    {
        public abstract void Move();
    }
    
    public class FirstDeviceViewModel : RS232DeviceViewModel
    {
        public override void Move()
        {
            throw new NotImplementedException();
        }
    }
    
    public class SecondDeviceViewModel : RS232DeviceViewModel
    {
        public override void Move()
        {
            throw new NotImplementedException();
        }
    }
    

    In your MainWindowViewModel, you would declare SelectedViewModel as an RS232DeviceViewModel:

    public class MainWindowViewModel
    {
        private RS232DeviceViewModel selectedViewModel
    
        public RS232DeviceViewModel SelectedViewModel
        {
            get
            {
                return selectedViewModel;
            }
            set
            {
                if (selectedViewModel != value)
                {
                    selectedViewModel = value;
                    OnPropertyChanged();
                }
            }
        }
    }