Home > database >  change property of singleton from another singleton?
change property of singleton from another singleton?

Time:12-05

I am trying to change the property "MyText" of the class "MainViewModel" from the class "ClassA" under MVVM. I'm not sure if I'm doing this correctly. Here's my code.

<Window.DataContext>
         <local:MainViewModel/>
     </Window.DataContext>
     <Grid>
         <StackPanel Orientation="Vertical">
             <TextBlock Text="{Binding MyText}"
                        Margin="50"/>
             <Button Content="Main Class"
                     Width="150"
                     Height="70"
                     Margin="50"
                     Command="{Binding Cmd}"
                     CommandParameter="MainClass"/>
    
             <Button Content="Class A"
                     Width="150"
                     Height="70"
                     Command="{Binding Cmd}"
                     CommandParameter="ClassA" />
         </StackPanel>
     </Grid>
    public class MainViewModel : BaseViewModel
    {
        private static MainViewModel instance = new MainViewModel();
        static MainViewModel()
        {
            instance = new MainViewModel();
        }
        public static MainViewModel Instance
        {
            get => instance;
        }
        private string myText = string.Empty;
        public string MyText
        {
            get
            {
                return myText;
            }
            set
            {
                if( myText != value)
                {
                    myText = value;
                    OnPropertyChanged();
                }
            }
        }
        public RelayCommand Cmd { get => new RelayCommand(CmdExec); }
        private void CmdExec(object parameter)
        {
            switch (parameter.ToString())
            {
                case "MainClass":
                    try
                    {
                        MyText = "I am from Class -> MainViewModel!";
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;

                case "ClassA":
                    try
                    {
                       // MyText = "I'am from Class -> ClassA!";
                        ClassA.Instance.ChangeText();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;
                default:
                    break;
            }
        }
    }
    public class ClassA
    {
        private static readonly ClassA instance=new ClassA();

        static ClassA()
        {
           
        }
        private ClassA() { }
        public static ClassA Instance
        {
            get => instance;
        }
        public void ChangeText()
        {
            MainViewModel.Instance.MyText = "I'am from Class -> ClassA!";
        }
    }
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public RelayCommand(Action<object> execute)
            : this(execute, null)
        {
        }
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested  = value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }

Unfortunately it does not work for me. It should be a simple call. Does anyone have any idea what might be doing wrong? What should I do?

CodePudding user response:

Because DataContext is set to another instance of MainViewModel.

 <Window.DataContext>
     <local:MainViewModel/>
 </Window.DataContext>

You still have public constructor of MainViewModel, so the code above creates a new instance of MainViewModel.

You need to have private constructor of MainViewModel to make sure that the only one instance of a class can ever be created.

public class MainViewModel : BaseViewModel
{
    private static MainViewModel instance = new MainViewModel();
    static MainViewModel()
    {
        instance = new MainViewModel();
    }
    private MainViewModel(){}
    public static MainViewModel Instance
    {
        get => instance;
    }
    ...
}

Then you need to set DataContext of MainWindow in code behind

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = MainViewModel.Instance;
    }
    ...
}

Get rid of

<Window.DataContext>
     <local:MainViewModel/>
 </Window.DataContext>

CodePudding user response:

I will supplement the answer of @user2250152. The method he proposed for obtaining a Singleton instance in Code Behind is often very inconvenient in Design Mode, since Code Behind is not executed in this Mode. You can get the value in XAML:

<Window ---------------
        ---------------
        DataContext="{x:Static local:MainViewModel.Instance}">

P.S. Also, in your implementation, the instance field does not make sense.
You must use either an autoproperty or initialization on first call.

    public class SomeClass
    {
        private SomeClass() { }
        public static SomeClass Instance {get;} = new SomeClass();
    public class SomeClass
    {
        private static SomeClass? _instance;
        private SomeClass() { }
        public static SomeClass Instance => _instance ??= new SomeClass();
  • Related