WPF UI 使用

小占时光 2024-07-02 16:42:36 2485


介绍

      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等类似,如果使用得比较细致则需要找文档看了。

示例项目中会把需要注册的服务注册了,如果是自己创建的项目则需要自己注册。同时需要自己实现 ApplicationHostServicePageService。

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

 

 

最后一次修改 : 2025/1/23 上午3:29:30

优秀
123
分享
123
奶茶
123
文章版权声明:版权归原作者(小占时光)所有。未经明确书面许可,严禁任何个人或组织以任何形式进行商业性或非商业性的使用、转载或抄袭。
评论