I am making a preference center that needs to sync updates for two separate Switch toggles with the same boolean/ toggle value. I am using Xamarin Forms with C#. I have a ViewModel.cs file such as
namespace XamarinDemoApp
public class MyViewModel : INotifyPropertyChanged
{
private bool swithOne;
public bool SwithOne
{
set
{
if (swithOne != value)
{
swithOne = value;
OnPropertyChanged("SwithOne");
}
}
get
{
return swithOne;
}
}
public MyViewModel()
{
SwithOne = true; // assign a value for `SwithOne `
}
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;
}
}
Then my AllowSaleToggleTab.xaml.cs looks like
namespace XamarinDemoApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AllowSaleToggleTab : ContentPage
{
MyViewModel myViewModel;
public AllowSaleToggleTab()
{
InitializeComponent();
myViewModel = new MyViewModel();
BindingContext = myViewModel;
}
}
}
The other toggle tab is PC.xaml.cs
namespace XamarinDemoApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PC : ContentPage
{
MyViewModel myViewModel;
public PC()
{
InitializeComponent();
Console.WriteLine("PC Initialized");
myViewModel = new MyViewModel();
BindingContext = myViewModel;
}
}
}
Finally, both my accompanying PC.xaml and AllowSaleToggleTab.xaml files have the elements
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:xamarindemoapp="clr-namespace:XamarinDemoApp" x:DataType="xamarindemoapp:MyViewModel"
x:Class="XamarinDemoApp.AllowSaleToggleTab">
<Switch x:Name="ToggleSwitch1" IsToggled="{Binding SwithOne}"/>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
Yet they still don't sync. Can anyone point out what I'm doing wrong? Thank you
CodePudding user response:
I don't know how your code is used,but there are several methods to achieve this.
For example,you can pass the data between two different Pages when navigating or use Xamarin.Forms MessagingCenter to send the data message between the two pages.
You can refer to the following code(I combined the two methods above):
TestPage1.xaml
<ContentPage.Content>
<StackLayout>
<Switch x:Name="toggleSwitch1" IsToggled="{Binding SwithOne}" HorizontalOptions="Center">
</Switch>
<Button Text="navigate to Page2" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage.Content>
TestPage1.xaml.cs
public partial class TestPage1 : ContentPage
{
MyViewModel myViewModel;
public TestPage1()
{
InitializeComponent();
myViewModel = new MyViewModel();
BindingContext = myViewModel;
}
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync( new TestPage2(myViewModel.SwithOne));//myViewModel.SwithOne
}
}
MyViewModel.cs
public class MyViewModel: INotifyPropertyChanged
{
private bool _swithOne { get; set; }
public bool SwithOne
{
set
{
if (_swithOne != value)
{
_swithOne = value;
OnPropertyChanged("SwithOne");
}
}
get
{
return _swithOne;
}
}
public MyViewModel()
{
SwithOne = true;
MessagingCenter.Subscribe<object, object>(this, "PassDataToOne", (sender, args) =>
{
bool value = (bool)args;
if (value!= SwithOne) {
SwithOne = value;
}
});
}
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;
}
TestPage2.xaml
<ContentPage.Content>
<StackLayout>
<Switch x:Name="toggleSwitch2" IsToggled="{Binding SwithTwo}" HorizontalOptions="Center" />
<Button Text="Navigate To Page 1" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage.Content>
TestPage2.xaml.cs
public partial class TestPage2 : ContentPage
{
MyViewModel2 myViewModel;
public TestPage2(bool isToggled)
{
InitializeComponent();
myViewModel = new MyViewModel2(isToggled);
BindingContext = myViewModel;
}
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PopAsync();
}
}
MyViewModel2.cs
public class MyViewModel2: INotifyPropertyChanged
{
private bool _swithTwo;
public bool SwithTwo
{
set
{
if (_swithTwo != value)
{
_swithTwo = value;
OnPropertyChanged("SwithTwo");
MessagingCenter.Send<object, object>(this, "PassDataToOne", _swithTwo);
}
}
get
{
return _swithTwo;
}
}
public MyViewModel2( bool isToggled)
{
SwithTwo = isToggled;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Note:
1.I Used two different ViewModels for the two pages(TestPage1
and TestPage2
), TestPage1's ViewModel is MyViewModel
, and TestPage1's ViewModel is MyViewModel2
.
2.After changing the status of Switch
in TestPage1
,we can pass the value SwithOne
in MyViewModel.cs
to TestPage2
by the Constructor:
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync( new TestPage2(myViewModel.SwithOne));//myViewModel.SwithOne
}
3.If we change the value of SwithTwo
in TestPage2
,we can use MessagingCenter
to send the value to TestPage1
:
public class MyViewModel2: INotifyPropertyChanged
{
private bool _swithTwo;
public bool SwithTwo
{
set
{
if (_swithTwo != value)
{
_swithTwo = value;
OnPropertyChanged("SwithTwo");
MessagingCenter.Send<object, object>(this, "PassDataToOne", _swithTwo);
}
}
get
{
return _swithTwo;
}
}
// other code
}
CodePudding user response:
the simplest way I know is to use a static object.
Variable Holder:
public class SomeClass : INotifyPropertyChanged
{
public static SomeClass Instance {get;set;} = new SomeClass();
public string SharedString {get;set;}
#region The rest of property changed
...
#endregion
}
View 1
<Label Text={Binding Path=SharedString, Source={x:Static locationOfSomeClass:SomeClass.Instance}} />
View 2
<Label Text={Binding Path=SharedString, Source={x:Static locationOfSomeClass:SomeClass.Instance}} />
And whenever you change the string, like SomeClass.Instance.SharedString = "I'm updating this string"; you get an updated string in both locations. Make sure you have propertychanged.fody nuget installed.