.NET Maui数据绑定到Shell Flyout项的IsVisible属性

3
所以我有一个弹出菜单,并且需要在特定条件下使弹出项消失。为了帮助我发展我的思路和理解,我有一个6个项目的弹出菜单,其中一个标题为 Bluetooth。我在第一个弹出页面中创建了一个名为 ShowParameters 的按钮。我可以通过点击此按钮使视图模型中的属性为 true 或 false。这似乎运行良好。我已将 Bluetooth 弹出项的 IsVisible 属性绑定到此 ShowParameters 属性。在单击按钮时,这不会更新 IsVisible 属性。似乎 PropertyChanged?.Invoke 没有链接到 Flyout 项,或者 Flyout 项没有链接到该属性,尽管我可以在 xaml 中自己使其出现或消失。显然,在这方面我是个新手,我可能做了什么很愚蠢的事情。请问有人能指出我犯了多么愚蠢的错误吗?

AppShell.xaml

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="TSDZ2Monitor.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:sys="clr-namespace:System;assembly=netstandard"
  
    xmlns:local="clr-namespace:TSDZ2Monitor"

    xmlns:pages="clr-namespace:TSDZ2Monitor.Pages"
  
    Shell.FlyoutBehavior="Flyout"
    FlyoutHeaderBehavior="Default"
    FlyoutVerticalScrollMode="Auto"
    FlyoutBackgroundColor="{StaticResource FlyoutBackgroundColor}">

  <Shell.BindingContext>
    <local:ShowParametersViewModel/>
  </Shell.BindingContext>

  <Shell.FlyoutHeaderTemplate>
    <DataTemplate>
      <Grid BackgroundColor="{StaticResource FlyoutBackgroundColor}"
            HeightRequest="200">
        <Image 
               HeightRequest="200"
               Source="bicycle.svg"
               Margin="10, 10, 10, 10"
               Opacity="0.6" />
        <Label Text="TSDZ2 Monitor"
               TextColor="White"
               FontAttributes="Bold" />
      </Grid>
    </DataTemplate>
  </Shell.FlyoutHeaderTemplate>

  <Shell.FlyoutFooterTemplate>
    <DataTemplate>
      <StackLayout>
        <Label Text="TSDZ2"
               TextColor="GhostWhite"
               FontAttributes="Bold"
               HorizontalOptions="Center" />
        <Label Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat='{0:MMMM dd, yyyy}'}"
               TextColor="GhostWhite"
               HorizontalOptions="Center" />
      </StackLayout>
    </DataTemplate>
  </Shell.FlyoutFooterTemplate>


  <Shell.ItemTemplate>
    <DataTemplate>
      <Grid ColumnDefinitions="0.2*, 0.8*">
        <Image Grid.Column="0" 
               Source="{Binding FlyoutIcon}"
               Margin="0, 20, 0, 10"
               VerticalOptions="Center"
               HeightRequest="30" />
        <Label Grid.Column="1"
               Text="{Binding Title}"
               TextColor="Yellow"
               FontSize="20"
               FontAttributes="Bold"
               VerticalTextAlignment="Center" />
      </Grid>
    </DataTemplate>
  </Shell.ItemTemplate>


  <ShellContent 
    Title="Display"
    Icon="speedometer.svg"
    ContentTemplate="{DataTemplate pages:DisplayPage}" />
  
  <ShellContent 
    Title="Bluetooth"
    Icon="bluetooth.svg"
    IsVisible="{Binding ShowParameters}"
    ContentTemplate="{DataTemplate pages:BluetoothPage}" />



  <ShellContent 
    Title="About"
    Icon="about.svg"
    ContentTemplate="{DataTemplate pages:AboutPage}" />

</Shell>

在 Pages 文件夹中的 DisplayPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             
             xmlns:local="clr-namespace:TSDZ2Monitor"
             
             x:Class="TSDZ2Monitor.Pages.DisplayPage"
             Title="Display Page">

  <ContentPage.BindingContext>
    <local:ShowParametersViewModel />
  </ContentPage.BindingContext>

  <StackLayout>
    <Label Text="Main Display"
           VerticalOptions="Center" 
           HorizontalOptions="Center" />
    
    <Button Text="Show parameters" 
            FontSize="20"
            Command="{Binding ShowParametersCommand}"/>
  </StackLayout>
</ContentPage>


我的ShowParametersViewModel.cs文件(在ViewModels文件夹中)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace TSDZ2Monitor
{
  //public class ShowParametersViewModel : BindableObject
  public class ShowParametersViewModel : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    bool showParameters = true;
    public bool ShowParameters
    {
      get { return showParameters; }
      set
      {
        if (value == showParameters) return;
        showParameters = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ShowParameters"));
      }
    }

    public ICommand ShowParametersCommand => new Command(ChangeShowParameters);

    public void ChangeShowParameters()
    {
      Console.WriteLine($"Before {ShowParameters}");
      ShowParameters = !ShowParameters;
      Console.WriteLine($"After {ShowParameters}");
     }
  }
}

如果我在AppShell.xaml中更改Shell.BindingContext,代码如下:
  <Shell.BindingContext>
    <local:ShowParametersViewModel  ShowParameters="false"/>
  </Shell.BindingContext>

这会使蓝牙弹出菜单项消失,反之亦然。

1个回答

5
问题发生的原因是你在不同页面之间操纵了不同的数据(视图模型),但我们需要共享数据。
以下两部分代码完全相同。
<Shell.BindingContext>
    <local:ShowParametersViewModel />
</Shell.BindingContext>

public AppShell()
{
    InitializeComponent();
    BindingContext = new ShowParametersViewModel();
}

实际上,它创建了一个 ViewModel 类的新实例,并将其设置为 BindingContext,与 DisplayPage 中的方法相同。

因此,有两个不同的 ViewModels,你只更改了 A,但 B 从未被更改。

解决方案

在代码后台中初始化 ShowParametersViewModel 而不是在 xaml(DisplayPage) 中,这样它们将共享同一个 ViewModel。

public DisplayPage ()
{
    InitializeComponent();
    this.BindingContext = AppShell.Current.BindingContext;
}

1
太酷了。我也感谢解释,不过我需要好好思考一下。非常感谢 :) - gfmoore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接