【问题标题】:How to bind two Switch controls in separate classes to the same bool property?如何将不同类中的两个 Switch 控件绑定到同一个 bool 属性?
【发布时间】: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(此处:stackoverflow.com/questions/69934877/…
  • 啊,这是有道理的,但是我的 XamarinDemoApp.android 包中有一个 MainActivity.cs,我的 XamarinDemoApp 包中有一个 App.xaml.cs 文件。我应该在哪里创建父实例?
  • 如果两个页面都在 Forms 项目中,把它放在那里。你也可以使用单例模式,或者创建一个静态类等。有很多方法可以解决这个问题。

标签: c# xaml xamarin.forms xamarin.android toggle


【解决方案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
    }
    

    【讨论】:

      猜你喜欢
      • 2018-08-08
      • 1970-01-01
      • 1970-01-01
      • 2021-02-06
      • 1970-01-01
      • 2013-08-21
      • 2020-10-30
      • 2012-03-24
      • 1970-01-01
      相关资源
      最近更新 更多