I am trying to inform one ViewModel about changes in another ViewModel. For this matter I have tried to use MessagingCenter. However it looks like it does not work for some reason. Could someone drop some light, why I am not able to change colour of Label in one View from another?
HomeViewModel.cs:
using System;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace MessagingCenterApp.ViewModels
{
public class HomeViewModel : BaseViewModel
{
public HomeViewModel()
{
Title = "Home";
MessagingCenter.Subscribe<Object, Color>(this, "gaugeColor", (sender, arg) =>
{
this._gaugeColor = arg;
});
this.GaugeColor = Color.White;
}
private Color _gaugeColor;
public Color GaugeColor
{
get => _gaugeColor;
set
{
_gaugeColor = value;
OnPropertyChanged();
}
}
}
}
SettingsViewModel.cs:
using MessagingCenterApp.Models;
using MessagingCenterApp.Views;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace MessagingCenterApp.ViewModels
{
public class SettingsViewModel : BaseViewModel
{
public SettingsViewModel()
{
Title = "Settings";
MessagingCenter.Send<Object, Color>(this, "gaugeColor", Color.FromHex(this.GaugeColor));
}
private string _gaugeColor;
public string GaugeColor
{
get => Preferences.Get("GaugeColor", "#17805d");
set
{
Preferences.Set("GaugeColor", value);
this.OnPropertyChanged();
}
}
}
}
EDIT:
Implementation without separate button:
SettingsViewModel.cs:
using MessagingCenterApp.Models;
using MessagingCenterApp.Views;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace MessagingCenterApp.ViewModels
{
public class SettingsViewModel : BaseViewModel
{
public ICommand changeCommand { get; set; }
public SettingsViewModel()
{
Title = "Settings";
GaugeColor = Color.Red;
changeCommand = new Command(changeColor);
}
private void changeColor()
{
GaugeColor = Color.FromHex(this.GaugeColorS);
MessagingCenter.Send<Object, Color>(this, "gaugeColor", GaugeColor);
}
private Color _gaugeColor;
public Color GaugeColor
{
get => _gaugeColor;
set
{
_gaugeColor = value;
this.OnPropertyChanged();
}
}
private string _gaugeColorS;
public string GaugeColorS
{
get => Preferences.Get("GaugeColor", "#17805d");
set
{
Preferences.Set("GaugeColor", value);
this.changeColor();
this.OnPropertyChanged();
}
}
}
}
HomeViewModel.cs:
using System;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace MessagingCenterApp.ViewModels
{
public class HomeViewModel : BaseViewModel
{
public HomeViewModel()
{
Title = "Home";
MessagingCenter.Subscribe<Object, Color>(this, "gaugeColor", (sender, arg) =>
{
System.Diagnostics.Debug.WriteLine("received color = " arg);
this.GaugeColor = arg;
});
this.GaugeColor = Color.Red;
}
private Color _gaugeColor;
public Color GaugeColor
{
get => _gaugeColor;
set
{
_gaugeColor = value;
OnPropertyChanged();
}
}
}
}
CodePudding user response:
If you want to send a message to another page when the property in current page is reset, you should add a event trigger (for example clicking a 'Button' in page SettingsPage
. Once the button is clicked,send a message to page HomePage
).
I simplified your code,and it works properly on my side. You can modify it to suit your needs.
BaseViewModel.cs
public class BaseViewModel : INotifyPropertyChanged
{
public IDataStore<Item> DataStore => DependencyService.Get<IDataStore<Item>>();
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
public bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
HomeViewModel.cs
public class HomeViewModel : BaseViewModel
{
private Color _gaugeColor;
public Color GaugeColor
{
set { SetProperty(ref _gaugeColor, value); }
get { return _gaugeColor; }
}
public HomeViewModel()
{
Title = "Home";
MessagingCenter.Subscribe<Object, Color>(this, "gaugeColor", (sender, arg) =>
{
System.Diagnostics.Debug.WriteLine("received color = " arg);
this.GaugeColor = arg;
});
this.GaugeColor = Color.Red;
}
}
SettingsViewModel.cs
public class SettingsViewModel : BaseViewModel
{
public ICommand changeCommand { get; set; }
public SettingsViewModel()
{
Title = "Settings";
GaugeColor = Color.Red;
changeCommand = new Command(changeColor);
}
private void changeColor(object obj)
{
GaugeColor = Color.Yellow;
MessagingCenter.Send<Object, Color>(this, "gaugeColor", GaugeColor);
}
Color _gaugeColor;
public Color GaugeColor
{
set { SetProperty(ref _gaugeColor, value); }
get { return _gaugeColor; }
}
}
SettingsPage.xaml (here I add Button )
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MessagingCenterApp.Views.SettingsPage"
Title="{Binding Title}"
xmlns:vm="clr-namespace:MessagingCenterApp.ViewModels"
Background="#121212"
x:Name="BrowseItemsPage">
<ContentPage.BindingContext>
<vm:SettingsViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="Accent">#0d1117</Color>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Orientation="Vertical">
<Label Text="Gauge color:"></Label>
<Entry Text="{Binding GaugeColor}" Keyboard="Numeric"></Entry>
<Button Text="change color" Command="{Binding changeCommand}"/>
</StackLayout>
</ContentPage>
Update:
I mean when I type or select new colour on Settings page, I would like to see new colour already
For this, you can add MessagingCenter.Send
in SettingsViewModel
as follows:
Color _gaugeColor;
public Color GaugeColor
{
set {
SetProperty(ref _gaugeColor, value);
MessagingCenter.Send<Object, Color>(this, "gaugeColor", GaugeColor);
}
get { return _gaugeColor; }
}
And if you don't want the Button, you can remove the Button
in SettingsPage.xaml
.