UWP Две радиокнопки, использующие двустороннюю привязку, перестают работать после навигации по страницам - PullRequest
0 голосов
/ 12 января 2019

У меня есть две переключатели, которые используют двустороннюю привязку к двум логическим свойствам, X и Y моей модели представления. Поскольку переключатели являются взаимоисключающими, настройка X автоматически очищает Y и наоборот. Теперь, если я перехожу на другую страницу, затем возвращаюсь, перехожу на нее и возвращаюсь на страницу с переключателями, кнопки перестают работать.

Действия по воспроизведению проблемы:

  1. Создание нового универсального пустого приложения для Windows на C #.
  2. Установите минимальную и целевую версию на 1809 (проблема сохраняется для 1803 и Обновления Создателей Падения)
  3. В файле App.xaml.cs добавьте следующий код перед строкой sealed partial class App : Application (включая System.ComponentModel и System.Runtime.CompilerServices пространства имен)

    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));
    }
    

    и в классе App, добавить

    public static ViewModel VM = new ViewModel();
    
  4. В файле MainPage.xaml замените содержимое страницы на

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

    и в MainPage.xaml.cs заменить MainPage class на

    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. Добавьте пустую страницу в ваш проект и в его файле .xaml замените содержимое страницы на

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

    и в его файл .cs добавить следующий обработчик кнопки

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Frame.Navigate(typeof(MainPage));
    }
    
  6. Скомпилируйте и запустите приложение, и после его запуска нажмите на переключатели, чтобы убедиться, что они работают.

  7. Нажмите Навигация, затем нажмите Назад. На этом этапе работают переключатели.

  8. Еще раз нажмите Навигация, а затем нажмите Назад. Кнопки больше не работают.

Что заставляет кнопки перестать работать? Это ошибка или я что-то упустил, и поведение ожидается? Спасибо.

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Перво-наперво, лучше всего инициализировать вашу Core ViewModel даже до того, как пользовательский интерфейс будет полностью загружен, это просто делает связывание более плавным.

Для этого создайте объект Datacontext в XAML. внутри

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

для защиты вашего dataconext создайте свойство Get only внутри класса Page, например

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

С учетом сказанного и выполненного, давайте упростим это.

Вам нужна только одна привязка свойства, и поскольку у вас есть только 2 варианта, вместо этого вы должны использовать два флажка друг над другом, первый флажок будет привязан к обычному значению свойства, а другой флажок будет противоположным .

Обратите внимание, что флажки IsChecked на самом деле являются логическими значениями, допускающими обнуление (bool?). как уже упоминалось ранее, для достижения этой единой системы свойств вам придется использовать так называемый A Converter , который в нашем случае просто обратит входящее значение, все это может показаться сложным, но я уверяю вас, это самое чистое и самый эффективный способ достижения такой функциональности.

Пример кода: 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>

это все написано в верхней части головы и на ноге, поэтому извините за форматирование, редактор слишком тусклый и неуклюжий, не разбивайте выражения связывания на разные строки, даже если они кажутся многострочными.

Редактирование: сборка Построить свой проект полезно после каждого шага, поскольку очень часто элементы, не относящиеся к пользовательскому фреймворку, такие как простой класс или конвертер, не сразу распознаются редактором xaml.

0 голосов
/ 12 января 2019

Попробуйте добавить название группы к вашим переключателям:

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

Это помогает?

...