页面导航后,使用双向绑定的UWP两个单选按钮停止工作

时间:2019-01-12 08:10:22

标签: c# uwp xaml-binding

我有两个单选按钮,它们使用双向绑定到视图模型的两个布尔属性XY。由于单选按钮是互斥的,因此设置X会自动清除Y,反之亦然。现在,如果我导航到另一个页面,请返回,再次导航到该页面,然后使用单选按钮返回该页面,按钮将停止工作。

重现该问题的步骤:

  1. 创建一个新的C#通用Windows空白应用程序。
  2. 将最低版本和目标版本设置为1809(1803和Fall Creators Update仍然存在该问题)
  3. 在App.xaml.cs中,在第sealed partial class App : Application行之前添加以下代码(请包含System.ComponentModelSystem.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类替换为

    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 :(得分:2)

尝试在单选按钮中添加组名:

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

有帮助吗?

答案 1 :(得分:0)

首先,最好在UI完全加载之前初始化Core ViewModel,这会使绑定更平滑。

为此,请在XAML上创建Datacontext对象。

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

要引用您的dataconext,请在Page类之内创建“仅获取”属性,例如

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

说了这么多,就简化了。

您只需要一个“属性绑定”,并且由于只有两个选项,因此应该在彼此上方使用两个复选框,第一个复选框将绑定到属性的常规值,而另一个复选框则相反

请注意,复选框 IsChecked 实际上是可为空的布尔值(布尔值)。如前所述,为了实现这一单一财产制度,您将必须使用称为 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>

所有内容都是从头顶和脚底写出来的,因此请原谅格式,编辑器太迟钝和笨拙,即使绑定表达式看起来像是多行,也不要将其分解成不同的行。

Edit:build最好在每个步骤之后构建项目,因为xaml编辑器通常不会立即识别诸如普通类或转换器之类的非ui frameork元素。