WinUI3中实现事件回调:Toolbar按钮触发Content框架切换
问题描述
我有一个主XAML页面,包含Toolbar和Content两个Frame,并且为这两个Frame准备了多个不同页面。Toolbar框架里用了CommandBar,请问怎么通过Toolbar框架(比如TaskerToolbar)内的AppBarButton点击事件,在MainPage中切换Content框架?或者说怎么把TaskerToolbar的点击事件传递到MainPage.xaml?感谢帮助。
现有代码
MainPage.xaml
<Grid> <Grid.RowDefinitions> <!-- toolbar--> <RowDefinition Height="110"/> <RowDefinition/> </Grid.RowDefinitions> <Border CornerRadius="0,0,0,10" BorderThickness="0,0,0,5"> <Border.BorderBrush> <LinearGradientBrush StartPoint=".5,0" EndPoint=".5,1" Opacity="0.02"> <GradientStop Color="Gray" Offset="0"/> <GradientStop Color="Black" Offset=".03"/> <GradientStop Color="Black" Offset=".98"/> <GradientStop Color="Gray" Offset="1"/> </LinearGradientBrush> </Border.BorderBrush> <Border CornerRadius="0,0,0,10" BorderBrush="#D4D4D4" BorderThickness="1,0,0,1"> <!-- toolbar frame --> <Grid Grid.Row="0" Background="#F3F3F3"> <Frame x:Name="toolbarFrame"/> </Grid> </Border> </Border> <!-- content frame --> <Grid Grid.Row="1"> <Frame x:Name="contentFrame"/> </Grid> </Grid>
MainPage.xaml.cs
public MainChromeWindowView() { this.InitializeComponent(); toolbarFrame.Navigate(typeof(TaskerToolbar), null); contentFrame.Navigate(typeof(SingleAView), null); }
TaskerToolbar.xaml
<Grid> <CommandBar Style="{StaticResource OpenDownCommandBar}" HorizontalAlignment="Left" IsOpen="False" DefaultLabelPosition="Collapsed" Margin="0,15,0,0"> <AppBarButton Style="{StaticResource ImageAppBarButtonStyle}" LabelPosition="Default" Label="Recorder"> <AppBarButton.Content> <Image> <Image.Source> <SvgImageSource UriSource="/Assets/icons/icon1.svg"/> </Image.Source> </Image> </AppBarButton.Content> </AppBarButton> <AppBarButton Style="{StaticResource ImageAppBarButtonStyle}" LabelPosition="Default" Label="Configuration"> <AppBarButton.Content> <Image> <Image.Source> <SvgImageSource UriSource="/Assets/icons/icon2.svg"/> </Image.Source> </Image> </AppBarButton.Content> </AppBarButton> </CommandBar> </Grid>
解决方案
方法1:自定义事件传递(直接高效)
这种方式适合简单场景,通过在Toolbar页面定义自定义事件,让MainPage订阅并处理导航逻辑。
步骤1:修改TaskerToolbar的代码后台
添加自定义事件和按钮点击处理逻辑:
public partial class TaskerToolbar : Page { // 定义导航请求事件,传递目标页面类型 public event EventHandler<Type>? NavigateRequested; public TaskerToolbar() { InitializeComponent(); } private void RecorderButton_Click(object sender, RoutedEventArgs e) { // 触发事件,传递Recorder页面类型 NavigateRequested?.Invoke(this, typeof(RecorderView)); } private void ConfigurationButton_Click(object sender, RoutedEventArgs e) { // 触发事件,传递Configuration页面类型 NavigateRequested?.Invoke(this, typeof(ConfigurationView)); } }
步骤2:给TaskerToolbar的按钮绑定点击事件
在XAML中添加Click属性:
<Grid> <CommandBar Style="{StaticResource OpenDownCommandBar}" HorizontalAlignment="Left" IsOpen="False" DefaultLabelPosition="Collapsed" Margin="0,15,0,0"> <AppBarButton Style="{StaticResource ImageAppBarButtonStyle}" LabelPosition="Default" Label="Recorder" Click="RecorderButton_Click"> <AppBarButton.Content> <Image> <Image.Source> <SvgImageSource UriSource="/Assets/icons/icon1.svg"/> </Image.Source> </Image> </AppBarButton.Content> </AppBarButton> <AppBarButton Style="{StaticResource ImageAppBarButtonStyle}" LabelPosition="Default" Label="Configuration" Click="ConfigurationButton_Click"> <AppBarButton.Content> <Image> <Image.Source> <SvgImageSource UriSource="/Assets/icons/icon2.svg"/> </Image.Source> </Image> </AppBarButton.Content> </AppBarButton> </CommandBar> </Grid>
步骤3:在MainPage中订阅事件并处理导航
修改MainPage.xaml.cs,监听Toolbar的导航请求事件:
public MainChromeWindowView() { InitializeComponent(); toolbarFrame.Navigate(typeof(TaskerToolbar), null); // 订阅Frame导航完成事件,确保能获取到Toolbar实例 toolbarFrame.Navigated += ToolbarFrame_Navigated; contentFrame.Navigate(typeof(SingleAView), null); } private void ToolbarFrame_Navigated(object sender, NavigationEventArgs e) { // 获取当前Toolbar页面实例,订阅导航请求事件 if (e.Content is TaskerToolbar toolbar) { toolbar.NavigateRequested += Toolbar_NavigateRequested; } } private void Toolbar_NavigateRequested(object? sender, Type targetPageType) { // 切换ContentFrame的页面 contentFrame.Navigate(targetPageType, null); }
方法2:MVVM命令绑定(解耦架构)
如果项目采用MVVM模式,通过共享ViewModel实现命令绑定,更符合架构设计原则。
步骤1:定义导航ViewModel
using System.ComponentModel; using System.Windows.Input; public class NavigationViewModel : INotifyPropertyChanged { public ICommand NavigateCommand { get; } private Type? _targetPageType; public Type? TargetPageType { get => _targetPageType; set { _targetPageType = value; OnPropertyChanged(); } } public NavigationViewModel() { NavigateCommand = new RelayCommand<Type>(pageType => TargetPageType = pageType); } public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } // 实现基础RelayCommand public class RelayCommand<T> : ICommand { private readonly Action<T> _execute; private readonly Predicate<T>? _canExecute; public RelayCommand(Action<T> execute, Predicate<T>? canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object? parameter) => _canExecute?.Invoke((T)parameter!) ?? true; public void Execute(object? parameter) => _execute((T)parameter!); public event EventHandler? CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } }
步骤2:注册全局ViewModel
在App.xaml中将ViewModel注册为全局资源:
<Application.Resources> <local:NavigationViewModel x:Key="NavigationVM"/> </Application.Resources>
步骤3:TaskerToolbar绑定命令
修改XAML,将按钮的Command绑定到全局ViewModel的命令,并传递目标页面类型:
<Grid DataContext="{StaticResource NavigationVM}"> <CommandBar Style="{StaticResource OpenDownCommandBar}" HorizontalAlignment="Left" IsOpen="False" DefaultLabelPosition="Collapsed" Margin="0,15,0,0"> <AppBarButton Style="{StaticResource ImageAppBarButtonStyle}" LabelPosition="Default" Label="Recorder" Command="{Binding NavigateCommand}" CommandParameter="{x:Type local:RecorderView}"> <AppBarButton.Content> <Image> <Image.Source> <SvgImageSource UriSource="/Assets/icons/icon1.svg"/> </Image.Source> </Image> </AppBarButton.Content> </AppBarButton> <AppBarButton Style="{StaticResource ImageAppBarButtonStyle}" LabelPosition="Default" Label="Configuration" Command="{Binding NavigateCommand}" CommandParameter="{x:Type local:ConfigurationView}"> <AppBarButton.Content> <Image> <Image.Source> <SvgImageSource UriSource="/Assets/icons/icon2.svg"/> </Image.Source> </Image> </AppBarButton.Content> </AppBarButton> </CommandBar> </Grid>
步骤4:MainPage监听ViewModel变化
修改MainPage.xaml.cs,监听ViewModel的页面类型变化并导航:
public MainChromeWindowView() { InitializeComponent(); toolbarFrame.Navigate(typeof(TaskerToolbar), null); contentFrame.Navigate(typeof(SingleAView), null); // 获取全局ViewModel并订阅属性变化事件 var navigationVM = (NavigationViewModel)Application.Current.Resources["NavigationVM"]; navigationVM.PropertyChanged += NavigationVM_PropertyChanged; } private void NavigationVM_PropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(NavigationViewModel.TargetPageType) && sender is NavigationViewModel vm) { if (vm.TargetPageType != null) { contentFrame.Navigate(vm.TargetPageType, null); } } }
内容的提问来源于stack exchange,提问作者Biryukov Georgy
相关产品推荐
相关产品推荐

