Avalonia 主窗体嵌入子窗体
首先在Main中添加一句代码
窗体设计器代码如下
<UserControl xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:AvaloniaPlant01.ViewModels" mc:Ignorable="d" d:DesignWidth="1920" d:DesignHeight="1020" Width="1920" Height="1020" x:Class="AvaloniaPlant01.Views.MainView" xmlns:converters="clr-namespace:AvaloniaPlant01.Base" x:DataType="vm:MainViewModel"> <Design.DataContext> <vm:MainViewModel /> </Design.DataContext> <!-- 窗体控件代码开始--> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="300"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <!-- 第一列用于左侧栏--> <Grid Grid.Column="0" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="100"/> <RowDefinition Height="550" /> <RowDefinition /> </Grid.RowDefinitions> <!-- 第一列.第一行 Logo区域 --> <StackPanel Grid.Row="0" Orientation="Horizontal" Background="Transparent" Height="64" VerticalAlignment="Center"> <Image Source="/Assets/avalonia-logo.ico" Height="45" Margin="10,0,8,0"/> <TextBlock FontSize="24" Text ="Navigation menu" Foreground="Black" VerticalAlignment="Center" /> </StackPanel> <!-- 第一列.第二行 菜单区域 --> <Grid Grid.Row="1" Background="Transparent"> <StackPanel Margin="0,0,0,0" VerticalAlignment="Center" Orientation="Vertical"> <!-- Command绑定命令,CommandParameter传递参数 --> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="DashboardView" Content="  DashboardView" Margin="0,2,0,0" Classes="nav"/> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="DeviceView" Content="  DeviceView" Margin="0,2,0,0" Classes="nav"/> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="ExperimentView" Content="  ExperimentView" Margin="0,2,0,0" Classes="nav"/> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="SettingsView" Content="  SettingsView" Margin="0,2,0,0" Classes="nav"/> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="TagsView" Content="  TagsView" Margin="0,2,0,0" Classes="nav"/> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="TaskView" Content="  TaskView" Margin="0,2,0,0" Classes="nav"/> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="UserView" Content="  UserView" Margin="0,2,0,0" Classes="nav"/> <RadioButton Command="{Binding OpenWindowCommand}" CommandParameter="OtherView" Content="  OtherView" Margin="0,2,0,0" Classes="nav"/> </StackPanel> </Grid> <Grid Grid.Row="2" Background="Transparent"> <!-- 第1列.第三行 当前用户和头像 --> <StackPanel Margin="10,0,0,50" Orientation="Horizontal" Background="Transparent" Height="64" VerticalAlignment="Bottom"> <Image Source="avares://AvaloniaPlant01/Assets/Images/Man_png/Man03.png" Height="45" Margin="20,0,8,0"/> <TextBlock FontSize="24" Text ="User Name" Foreground="Black" VerticalAlignment="Center" /> </StackPanel> </Grid> </Grid> <!-- 第二列用于右侧容器 --> <Grid Grid.Column="1" Background="Transparent" > <ContentControl Margin="0,0,0,0" Content="{Binding Content}"> <ContentControl.ContentTemplate> <converters:ViewLocator /> </ContentControl.ContentTemplate> </ContentControl> </Grid> </Grid> </UserControl>
窗体模型 代码如下
using System; using System.Collections.ObjectModel; using System.Windows.Input; using Avalonia.Controls; using AvaloniaPlant01.Base; using AvaloniaPlant01.ViewModels.EmbeddedForm; using AvaloniaPlant01.Views; using CommunityToolkit.Mvvm.Messaging; namespace AvaloniaPlant01.ViewModels; public partial class MainViewModel : ViewModelBase { public ICommand OpenWindowCommand { get; set; } private object? _content; public object? Content { get => _content; set => SetProperty(ref _content, value); } public MainViewModel() { OpenWindowCommand = new Command(ExeOpenWindowCommand); WeakReferenceMessenger.Default.Register<MainViewModel, string>(this, OnNavigation); } private void OnNavigation(MainViewModel vm, string s) { Content = s switch { MenuKeys.MenuKeyDashboard => new DashboardViewModel(), MenuKeys.MenuKeyDevice => new DeviceViewModel(), MenuKeys.MenuKeyExperiment => new ExperimentViewModel(), MenuKeys.MenuKeySettings => new SettingsViewModel(), MenuKeys.MenuKeyTags => new TagsViewModel(), MenuKeys.MenuKeyTask => new TaskViewModel(), MenuKeys.MenuKeyUser => new UserViewModel(), MenuKeys.MenuKeyOther => new OtherViewModel(), _ => throw new ArgumentOutOfRangeException(nameof(s), s, null) }; } //打开窗体方法 private void ExeOpenWindowCommand(object obj) { OnNavigation(this, obj.ToString()); } }
using System; using Avalonia.Controls; using Avalonia.Controls.Templates; namespace AvaloniaPlant01.Base; /// <summary> /// 把嵌入子视图嵌入主窗体实体,需要使用 /// </summary> public class ViewLocator : IDataTemplate { public Control? Build(object? param) { if (param is null) return null; var name = param.GetType().Name.Replace("Model", ""); string strname = "AvaloniaPlant01.Views." + name; var type = Type.GetType("AvaloniaPlant01." + name); if (type != null) { return (Control)Activator.CreateInstance(type)!; } return new TextBlock { Text = "Not Found: " + name }; } public bool Match(object? data) { return true; } }
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using System.Windows.Input; namespace AvaloniaPlant01.ViewModels.EmbeddedForm { public enum ControlStatus { New, Beta, Stable, } public class MenuItemViewModel : ViewModelBase { public string? MenuHeader { get; set; } public string? MenuIconName { get; set; } public string? Key { get; set; } public string? Status { get; set; } public bool IsSeparator { get; set; } public ObservableCollection<MenuItemViewModel> Children { get; set; } = new(); public ICommand ActivateCommand { get; set; } public MenuItemViewModel() { ActivateCommand = new RelayCommand(OnActivate); } private void OnActivate() { if (IsSeparator || Key is null) return; WeakReferenceMessenger.Default.Send(Key); } } }
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AvaloniaPlant01.ViewModels.EmbeddedForm { public class MenuViewModel : ViewModelBase { public ObservableCollection<MenuItemViewModel> MenuItems { get; set; } public MenuViewModel() { MenuItems = new ObservableCollection<MenuItemViewModel>() { new() { MenuHeader = "DashboardView", Key = MenuKeys.MenuKeyDashboard, IsSeparator = false }, new() { MenuHeader = "DeviceView", Key = MenuKeys.MenuKeyDevice, IsSeparator = false }, new() { MenuHeader = "ExperimentView", Key = MenuKeys.MenuKeyExperiment, IsSeparator = false }, new() { MenuHeader = "OtherView", Key = MenuKeys.MenuKeyOther, IsSeparator = false }, new() { MenuHeader = "SettingsView", Key = MenuKeys.MenuKeySettings, IsSeparator = false }, new() { MenuHeader = "TagsView", Key = MenuKeys.MenuKeyTags, IsSeparator = false }, new() { MenuHeader = "TaskView", Key = MenuKeys.MenuKeyTask, IsSeparator = false }, new() { MenuHeader = "UserView", Key = MenuKeys.MenuKeyUser, IsSeparator = false }, }; } } public static class MenuKeys { public const string MenuKeyDashboard = "DashboardView"; public const string MenuKeyDevice = "DeviceView"; public const string MenuKeyExperiment = "ExperimentView"; public const string MenuKeyOther = "OtherView"; public const string MenuKeySettings = "SettingsView"; public const string MenuKeyTags = "TagsView"; public const string MenuKeyTask = "TaskView"; public const string MenuKeyUser = "UserView"; } }
下面看看结果展示
(当前第三集 主窗体嵌入子窗体 下一集 用户登录管理)