如何将不同类中的两个 Switch 控件绑定到同一个 bool 属性?

Posted

技术标签:

【中文标题】如何将不同类中的两个 Switch 控件绑定到同一个 bool 属性?【英文标题】:How to bind two Switch controls in separate classes to the same bool property? 【发布时间】:2021-12-29 18:56:34 【问题描述】:

我正在创建一个首选项中心,该中心需要为两个具有相同布尔/切换值的单独切换切换同步更新。我正在使用带有 C# 的 Xamarin 表单。我有一个 ViewModel.cs 文件,例如

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;

    

然后我的 AllowSaleToggleTab.xaml.cs 看起来像

namespace XamarinDemoApp

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AllowSaleToggleTab : ContentPage

    MyViewModel myViewModel;
    public AllowSaleToggleTab()
    
        InitializeComponent();
        myViewModel = new MyViewModel();
        BindingContext = myViewModel;
    


另一个切换选项卡是 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;
    


最后,我随附的 PC.xamlAllowSaleToggleTab.xaml 文件都有这些元素

<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"/>

但它们仍然不同步。谁能指出我做错了什么?谢谢

【问题讨论】:

每个页面都有自己的虚拟机实例。同一类的多个实例完全相互独立 您创建不同的 ViewModel 实例,每个实例用于每个页面。两个页面都应该是单一的。就像我之前对 WPF 的回答一样,我在一个窗口中创建实例,然后将其作为参数传递给其他两个,因此它们使用相同的 ViewModel(此处:***.com/questions/69934877/…) 啊,这是有道理的,但是我的 XamarinDemoApp.android 包中有一个 MainActivity.cs,我的 XamarinDemoApp 包中有一个 App.xaml.cs 文件。我应该在哪里创建父实例? 如果两个页面都在 Forms 项目中,把它放在那里。你也可以使用单例模式,或者创建一个静态类等。有很多方法可以解决这个问题。 【参考方案1】:

我知道的最简单的方法是使用静态对象。

变量持有人:

public class SomeClass : INotifyPropertyChanged

public static SomeClass Instance get;set; = new SomeClass();

public string SharedString get;set;

#region The rest of property changed
...
#endregion

查看 1

<Label Text=Binding Path=SharedString, Source=x:Static locationOfSomeClass:SomeClass.Instance />

查看 2

<Label Text=Binding Path=SharedString, Source=x:Static locationOfSomeClass:SomeClass.Instance />

每当您更改字符串时,例如 SomeClass.Instance.SharedString = "我正在更新此字符串";您在两个位置都会获得更新的字符串。确保您已安装 propertychanged.fody nuget。

【讨论】:

【参考方案2】:

我不知道你的代码是如何使用的,但是有几种方法可以实现。

例如,您可以在导航时在两个不同的Page之间传递数据,或者使用Xamarin.Forms MessagingCenter在两个页面之间发送数据消息。

你可以参考下面的代码(我结合了上面的两种方法):

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;

注意:

1.我为两个页面使用了两个不同的ViewModel(TestPage1TestPage2),TestPage1的ViewModel是MyViewModel,TestPage1的ViewModel是MyViewModel2

2.改变TestPage1Switch的状态后,我们可以通过构造函数将MyViewModel.cs中的SwithOne值传递给TestPage2

    private async void Button_Clicked(object sender, EventArgs e)
    
        await Navigation.PushAsync( new TestPage2(myViewModel.SwithOne));//myViewModel.SwithOne
    

3.如果我们改变TestPage2SwithTwo的值,我们可以使用MessagingCenter将值发送给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

【讨论】:

以上是关于如何将不同类中的两个 Switch 控件绑定到同一个 bool 属性?的主要内容,如果未能解决你的问题,请参考以下文章

Android 多个控件绑定同一个PopupWindow,当点击popupWindow中的控件时获取到触发popWindow控件的文本

从其他 Xaml 文件绑定到用户控件中的元素

QT将不同类的信号和插槽连接到主窗口类?

将datagrid WPF绑定到带有列表的两个不同类?

这会导致集合中的两个绑定绑定到同一个属性。参数名称:c#中的绑定错误?

将自定义控件内的 TextBlock 绑定到同一自定义控件的依赖属性