ArtZaqX__
ArtZaqX__

Reputation: 13

UWP Two Radio Buttons using two-way binding stop working after page navigation

I have two radio buttons which are using two-way binding to two boolean properties, X and Y of my view model. Since radio buttons are mutually exclusive, setting X automatically clears Y and vice versa. Now, if I navigate to a different page, then come back, navigate to it again and come back to the page with radio buttons, the buttons stop working.

Steps to reproduce the problem:

  1. Create a new C# Universal Windows Blank App.
  2. Set min and target version to 1809 (the problem persists for 1803 and Fall Creators Update)
  3. In App.xaml.cs, add the following code before line sealed partial class App : Application (Do include System.ComponentModel and System.Runtime.CompilerServices namespaces)

    public class ViewModel : INotifyPropertyChanged
    {
        private bool _X;
        public bool X
        {
            get => _X;
            set
            {
                if (value != _X)
                {
                    _X = value;
                    OnPropertyChanged();
                }
            }
        }
    
        private bool _Y;
        public bool Y
        {
            get => _Y;
            set
            {
                if (value != _Y)
                {
                    _Y = value;
                    OnPropertyChanged();
                }
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    

    and in class App, add

    public static ViewModel VM = new ViewModel();
    
  4. In MainPage.xaml, replace page content with

    <StackPanel>
        <RadioButton IsChecked="{x:Bind VM.X, Mode=TwoWay}" Content="X"/>
        <RadioButton IsChecked="{x:Bind VM.Y, Mode=TwoWay}" Content="Y"/>
        <Button Content="Navigate" Click="Button_Click"/>
    </StackPanel>
    

    and in MainPage.xaml.cs, replace MainPage class with

    public sealed partial class MainPage : Page
    {
        public ViewModel VM => App.VM;
    
        public MainPage()
        {
            InitializeComponent();
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Frame.Navigate(typeof(BlankPage1));
        }
    }
    
  5. Add a blank page to your project and in its .xaml file, replace its page content with

    <Grid>
        <Button Click="Button_Click" Content="Back"/>
    </Grid>
    

    and in its .cs file, add following button handler

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Frame.Navigate(typeof(MainPage));
    }
    
  6. Compile and launch the application and once it's running, click on the radio buttons to confirm that they are working.

  7. Click Navigate, then click Back. The radio buttons are working at this point.

  8. Once again, click Navigate and then click Back. The buttons no longer work.

What causes the buttons to stop working? Is this a bug or am I missing something and the behavior is expected? Thanks.

Upvotes: 1

Views: 1557

Answers (2)

Xeorge Xeorge
Xeorge Xeorge

Reputation: 462

First things first, it is best to initialize your Core ViewModel even before the ui is fully loaded, it just makes binding smoother.

To do this, create your Datacontext object on XAML. inside the

 <MainPage.DataContext>
<yourviewmodelnamespace:YourViewModel/>
</MainPage.DataContext> 
<Grid> 
etc....

to refence your dataconext create a Get only property inside the Page class like

public YourViewModel mydatacontext{
get{
return DataContext as YourViewModel;}
}

With that said and done lets simplify this.

You only need one Property Bind, and since you only have 2 options, you should use two checkboxes on top of each other instead, the first checkbox will bind to the normal value of the property and the other checkbox will be the opposite.

Do note that Checkboxes IsChecked is actually a nullable boolean (bool?). as mentioned earlier in order to achieve this one property system you will have to use what is called A Converter that in our case will simply reverse the incoming value, this all might seem complicated but i assure you its the cleanest and most efficient way of achieving such functionality.

Example Code: 1. YourViewModel.cs

  private bool? _y;
    public bool? IsYCheckboxChecked
    {
        get => _y;
        set
        {
            if (value != _y)
            {
                _Y = value;
                OnPropertyChanged();
            }
        }
    }
  1. ConverterClass
namespace YourConvertNameSpace{

public Class NullBoolReverser{// this is the converter we are going to use to reverse the bool?
 public object Convert(object value, Type targetType, object parameter, string language)
            {
                var val = (bool?)value;

                return !val;
            }

            public object ConvertBack(object value, Type targetType, object parameter, string language)
            {
                var val = (bool?)value;

                return !val;
            }
}


}
  1. MainPage.xaml
<MainPage.Resources>
    <YourConvertNameSpace:NullBoolReverser x:Key="MyReverserKey"/>
</MainPage.Resources>

<MainPage.DataContext>
    <your datacontextgoes here, like i showed before, it will be accessed by a get only prop called 'mydatacontext'>
    </MainPage.DataContext>

    <Grid>
        <StackPanel
            <CheckBox Name="Ycheckbox"  IsChecked="{x:Bind 'mydatacontext.IsYCheckboxChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                      This is Y
            </CheckBox

            <CheckBox IsChecked="{x:Bind Ycheckbox.IsChecked, Converter={StaticResource MyReverserKey}, Mode=TwoWay}">
                      This is X
            </CheckBox><!--This Bind Allows a and exclusive clause between the two cheboxes thanks to the nullbool reverser-->

        </StackPanel
    </Grid
</Page>

this is all is written out of the top of head and on the foot, so excuse the formatting, the editor is too lackluster and clunky, do not break bind expressions into different lines even if they appear to be multiline.

Edit:build it is good to Build your project after each step, as very often non ui frameork elements like a plain class or a converter will not instantly be reckognized by the xaml editor.

Upvotes: 0

Yves Israel
Yves Israel

Reputation: 408

Try to add a group name to your radio buttons:

<StackPanel>
    <RadioButton IsChecked="{x:Bind VM.X, Mode=TwoWay}" Content="X" GroupName="Group1"/>
    <RadioButton IsChecked="{x:Bind VM.Y, Mode=TwoWay}" Content="Y" GroupName="Group1"/>
    <Button Content="Navigate" Click="Button_Click"/>
</StackPanel>

Does it help?

Upvotes: 3

Related Questions