介绍
WPFUI 是一个为 WPF 应用程序提供现代化 UI 组件的框架,它旨在简化开发过程并增强用户界面体验。WPFUI 的目标是提供现代、直观且易于使用的控件和样式,帮助开发者更快地构建美观的应用程序。以下是对 WPFUI 框架的介绍:
主要特点
现代化设计:WPFUI 提供了一组符合现代设计规范的 UI 组件,使应用程序看起来更时尚和专业。
易用性:框架设计简洁,使用方便,开发者可以快速上手,并在项目中轻松集成 WPFUI 提供的控件和样式。
丰富的控件库:WPFUI 包含许多常用的控件,如按钮、文本框、菜单、对话框等,并且这些控件都经过精心设计,具有良好的用户体验。
高可定制性:开发者可以根据项目需求对 WPFUI 提供的控件进行自定义,从而实现符合特定要求的用户界面。
响应式布局:WPFUI 支持响应式布局,可以在不同大小的屏幕上保持良好的显示效果。
持续更新与支持:WPFUI 框架有活跃的开发社区和官方支持,定期发布更新和新特性,确保框架始终处于最新状态。
github地址:➤ https://github.com/lepoco/wpfui
文档地址:➤ https://wpfui.lepo.co/index.html
一,添加nuget包
添加命名空间xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
App.xaml中添加资源
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
此处有两种添加方式,还可以手动添加资源
<Application>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Wpf.Ui;component/Styles/Theme/Dark.xaml" />
<ResourceDictionary Source="pack://application:,,,/Wpf.Ui;component/Styles/Wpf.Ui.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
先添加一个图标试试,已经可以显示,证明主题样式已经添加到项目中了。
二、创建wpf-ui项目和文件项目中文件目录介绍
除了像上面一样直接添加引用外,WPFUI还可以直接创建标准的WPFUI项目,在扩展管理器中输入“wpf ui”,安装即可。安装后再创建新项目时,就会出现WPF UI 了。
创建WPF UI 项目后会默认创建需要的文件夹,同时也会有部分的实例代码,为了风格统一可以参考其代码风格。
项目创建的文目录简单介绍,虽然大概能猜到,但还是按自己理解描述一下:
Assets 常用的静态资源,比如软件用的到的图片图标等
Controls 自定义控件等
Helpers 放的是帮助类,例如值转换器等
Models 数据的模型类,例如实体类等
Resources 例如style文件等
Services 相关服务,例如IHostedService,IPageService这实现
ViewModels 视图的模型和交互
Views Window和Page等
app.manifest 配置应用程序的清单信息
App.xaml 定义应用程序级别的资源和事件处理程序(wpf项目都有这个文件)
AssemblyInfo 包含程序集级别的特性(Attributes),如标题、描述、版本等
Usings.cs 单个文件中定义全局 using 指令,这样在项目的其他地方就不需要重复这些 using 指令了
wpfui-icon.ico 软件图标
三、基础功能介绍
软件启动页面的修改,不是在app中直接指定启动页面了,这里需要注意,如果还是使用 StartupUri="MainWindow.xaml"方式,也可以启动,但是启动的页面就拿不到依赖注入里面的服务了,很多wpfui框架中的功能会使用不了哦!
依赖注入在ConfigureServices里面直接写就可以,注入的生命周期很常用autofac,prism等类似,如果使用得比较细致则需要找文档看了。
示例项目中会把需要注册的服务注册了,如果是自己创建的项目则需要自己注册。同时需要自己实现 ApplicationHostService和PageService。
services.AddHostedService<ApplicationHostService>();
// Page resolver service
services.AddSingleton<IPageService, PageService>();
services.AddSingleton<IContentDialogService, ContentDialogService>();
// Theme manipulation
services.AddSingleton<IThemeService, ThemeService>();
// TaskBar manipulation
services.AddSingleton<ITaskBarService, TaskBarService>();
// Service containing navigation, same as INavigationWindow... but without window
services.AddSingleton<INavigationService, NavigationService>();
// Main window with navigation
services.AddSingleton<INavigationWindow, MainWindow>();
services.AddSingleton<MainWindowViewModel>();
services.AddSingleton<DashboardPage>();
services.AddSingleton<DashboardViewModel>();
这里view 和viewmodel都要注册,使用的时候,直接在view中获取viewmodel,下面看一下示例代码就明白了。view要继承INavigableView<T>,里面有ViewModel属性。这里需要注意,DataContext = this,页面绑定时不要漏掉viewmodel,例如 Text="{Binding ViewModel.AppVersion, Mode=OneWay}",(本人再此处踩过坑,为什么不写成DataContext =viewModel,这样就可不用写viewmodel,有大佬知道的请帮忙解惑一下 )。
public partial class SettingsPage : INavigableView<SettingsViewModel>
{
public SettingsViewModel ViewModel { get; }
public SettingsPage(SettingsViewModel viewModel)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
}
}
WPF UI使用的MVVM 是微软的communitytoolkit ,所以对viewmodel 中的写法不了解的可以去看一下communitytoolkit 文档。简单介绍一下属性和命令,这两个是最常用的,
属性
属性只需要写一个私有即可,框架补齐监听代码
[ObservableProperty]
private string _appVersion = String.Empty;
原生wpf代码
private string _appVersion = string.Empty;
public string AppVersion
{
get => _appVersion;
set
{
if (_appVersion != value)
{
_appVersion = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
页面binding使用时,框架会生成AppVersion,即大写首字母命名属性,使用的时候就使用生成的这个属性,viewModle中私有的那个即使赋值页面也不会监听变化,需要直接赋值AppVersion。
<TextBlock Margin="0,12,0,0" Text="{Binding ViewModel.AppVersion, Mode=OneWay}" />
命令
在方法名上面添加RelayCommand,方法写私有方法
[RelayCommand]
private void OnChangeTheme(string parameter)
{
}
wpf 原生写法
using System;
using System.Windows.Input;
public class RelayCommand : ICommand
{
private readonly Action<string> _execute;
private readonly Func<bool> _canExecute;
public RelayCommand(Action<string> execute, Func<bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute();
}
public void Execute(object parameter)
{
_execute((string)parameter);
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
public class MyViewModel : INotifyPropertyChanged
{
private RelayCommand _changeThemeCommand;
public ICommand ChangeThemeCommand => _changeThemeCommand ??= new RelayCommand(OnChangeTheme);
private void OnChangeTheme(string parameter)
{
// Change theme logic
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
框架会帮忙生成 ChangeThemeCommand 命令,如果方法名前面带有On,后面带有Async的 生成的命令会忽略这些词,在最后加上Command。页面Binding时和wpf原生一样。
<RadioButton
Command="{Binding ViewModel.ChangeThemeCommand, Mode=OneWay}"
CommandParameter="theme_dark"
Content="Dark"
GroupName="themeSelect"
IsChecked="{Binding ViewModel.CurrentTheme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Dark, Mode=OneWay}" />
对于[RelayCommand] 微软有介绍文章
➤ https://learn.microsoft.com/zh-cn/dotnet/communitytoolkit/mvvm/generators/relaycommand
四,基础控件使用
基础控件使用,可以直接运行源码中的,Wpf.Ui.Gallery项目,需要什么控件可以直接搜索,运行效果如下:
使用控件不建议看软件后面带的Source code ,有些照着写了也不是同样的效果,要去vs中找效果示例代码。
vs 中是这样写的,惊不惊喜意不意外,所以为了避免不必要的麻烦,看到要用的控件,导航到示例项目里面,看它的效果是怎么实现的。
WPFUI 中很多控件样式是全局的,如果控件使用了自己 Style ,WPFUI样式就会失效,避免这种情况,可以使用继承它的基础样式 BasedOn="{StaticResource **BaseStyle}",**BaseStyle是你需要的控件的基础样式。
项目也还有一些小问题,例如github上有人提问的菜单字体过长会被截断,能自动调整长度的问题,我也遇到了,试了一些方法也不行,坐等大佬更新。
➤ https://github.com/lepoco/wpfui/issues/1057