Home > Software design >  Sharing ViewModel's properties between more views
Sharing ViewModel's properties between more views

Time:09-07

i'm new to WPF and MVVM but i trying to do a simple project. My application basically consist in one window with two TabItems and a common progress bar; inside each TabItem there are some control for FTP communication or similar. For its semplicity there is no need making it complicated with multiple views but i would like to make it cleanest as possible. My idea is to create three ViewModel, one for each TabItem and the other for the "common control", like the progress bar (used for the FTP transfer progress) and be able to access from TabItem1VM and TabItem2VM to CommonVM. I have read that a good approach could be using a singleton CommonVM, but how i deal with singleton if i want to implement INotifyPropertyChanged for the Progress bar property and some few more?

At the moment i sketched something like this, but i think is quite a mess:

internal class Notifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

 internal class ViewModelCommon : Notifier
{
    public static ViewModelCommon Instance = new ViewModelCommon();
    public bool OperationInProgress
    {
        get { return GetInstance().OperationInProgress; }
        set {
            GetInstance().OperationInProgress = value;
            OnPropertyChanged("OperationInProgress");
        }
    }
    private ViewModelCommon() { }

    internal static ViewModelCommon GetInstance()
    {
        if(Instance == null )
        {
            Instance = new ViewModelCommon();
        }
        return Instance;
    }

}

 internal class ViewModelBase : Notifier
{

    public ViewModelCommon VMCommmon
    {
        get { return ViewModelCommon.GetInstance(); }
    }

}

internal class ViewModel1 : ViewModelBase
{

}
internal class ViewModel2 : ViewModelBase
{

}

CodePudding user response:

You did the implementation a little wrong.
And in WPF, it's better to use public types unless encapsulation is explicitly specified in the job conditions.
Fix like this (.Net 5 ).

The first variant is the Singleton implementation.

public class ViewModelCommon : BaseInpc
{
    private static ViewModelCommon _instance
    public static ViewModelCommon Instance => _instance 
        ??= new ViewModelCommon();

    private bool _operationInProgress
    public bool OperationInProgress
    {
        get => _operationInProgress;
        set => Set(ref _operationInProgress, value);
    }
    private ViewModelCommon() { }
}

BaseInpc is my simple INotifyPropertyChanged implementation from here: BaseInpc

Binding to this class:

<CheckBox IsChecked="{Binding OperationInProgress, Source={x:Static vms:ViewModelCommon.Instance}}" .../>

vms: is the namespace prefix of the ViewModelCommon class.

The second variant is to create an instance in App resources.

public class ViewModelCommon : BaseInpc
{
    private bool _operationInProgress
    public bool OperationInProgress
    {
        get => _operationInProgress;
        set => Set(ref _operationInProgress, value);
    }
}
    <Application.Resources>
        <vms:ViewModelCommon x:Key="commonVM"
                             OperationInProgress="True"/>
    </Application.Resources>

The value of the OperationInProgress property is set as an example if the default value needs to be changed when the instance is created.

Binding to this instance:

<CheckBox IsChecked="{Binding OperationInProgress, Source={StaticResource commonVM}}" .../>
  • Related