(1/7).net core 3 wpf mvvm框架 prism系列之數據綁定

(1/7).net core 3 wpf mvvm框架 prism系列之數據綁定

數據綁定

最后更新 2023/6/10 下午11:30
RyzenAdorer
预计阅读 5 分钟
分类
WPF
专题
wpf mvvm框架 prism系列
标签
.NET C# WPF Prism MVVM

本文來自轉載

原文作者:ryzenadorer

原文標題:.net core 3 wpf mvvm 框架 prism 系列之數據綁定

原文連結:https://www.cnblogs.com/ryzen/p/11905866.html

一.安裝 prism

  1. 使用程式包管理控制台
Install-Package Prism.Unity -Version 7.2.0.1367

也可以去掉『-version 7.2.0.1367』獲取最新的版本

  1. 使用管理解決方案的 nuget 包

在上面或許我們有個疑問?為啥安裝 prism 會跟 prism.unity 有關係,我們知道 unity 是個 ioc 容器, 而 prism 本身就支持 ioc, 且目前官方支持幾種 ioc 容器:

    1. 且 unity 由於是微軟官方的,且支持 prism 的組件化,由此我推薦使用 prism.unity,在官方文檔中 prism7 不支持 prism.mef,prism 7.1 將不支持 prism.autofac
    1. 安裝完 prism.unity 就已經包含著所有 prism 的核心庫了,架構如下:

二.實現數據綁定

我們先創建 views 文件夾和 viewmodels 文件夾,將 mainwindow 放在 views 文件夾下,再在 viewmodels 文件夾下面創建 mainwindowviewmodel 類,如下:

xaml 代碼如下:

<Window
  x:Class="PrismSample.Views.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  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:prism="http://prismlibrary.com/"
  xmlns:local="clr-namespace:PrismSample"
  mc:Ignorable="d"
  Title="MainWindow"
  Height="450"
  Width="800"
  prism:ViewModelLocator.AutoWireViewModel="True"
>
  <StackPanel>
    <TextBox
      Text="{Binding Text}"
      Margin="10"
      Height="100"
      FontSize="50"
      Foreground="Black"
      BorderBrush="Black"
    />
    <button
      Height="100"
      Width="300"
      Content="Click Me"
      FontSize="50"
      Command="{Binding ClickCommnd}"
    />
  </StackPanel>
</Window>

viewmodel 代碼如下:

using Prism.Commands;
using Prism.Mvvm;

namespace PrismSample.ViewModels
{
   public class MainWindowViewModel:BindableBase
    {
        private string _text;
        public string Text
        {
            get { return _text; }
            set { SetProperty(ref _text, value); }
        }

        private DelegateCommand _clickCommnd;
        public DelegateCommand ClickCommnd =>
            _clickCommnd ?? (_clickCommnd = new DelegateCommand(ExecuteClickCommnd));

        void ExecuteClickCommnd()
        {
            this.Text = "Click Me!";
        }

        public MainWindowViewModel()
        {
            this.Text = "Hello Prism!";
        }
    }
}

啟動程式:

點擊 click me 按鈕:

可以看到,我們已經成功的用 prism 實現數據綁定了,且 view 和 viewmodel 完美的前後端分離

但是現在我們又引出了另外一個問題,當我們不想按照 prism 的規定硬要將 view 和 viewmodel 放在 views 和 viewmodels 裡面,又或許自己的項目取名規則各不相同怎麼辦,這時候就要用到另外幾種方法:

  1. 更改命名規則

如果,公司命名規則很變態,導致項目結構變成這樣(這種公司辭職了算了):

首先我們在 app 需要引入 prism,修改『application』為『prism:prismapplication』且刪除 startupuri

xaml 代碼如下:

<prism:PrismApplication
  x:Class="PrismSample.App"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:prism="http://prismlibrary.com/"
  xmlns:local="clr-namespace:PrismSample"
>
  <Application.Resources> </Application.Resources>
</prism:PrismApplication>

cs 後台代碼如下:

using Prism.Unity;
using Prism.Ioc;
using Prism.Mvvm;
using System.Windows;
using PrismSample.Viewsb;
using System;
using System.Reflection;

namespace PrismSample
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : PrismApplication
    {
        //设置启动起始页
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {

        }

        //配置规则
        protected override void ConfigureViewModelLocator()
        {
            base.ConfigureViewModelLocator();
            ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
            {
                var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
                var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
                var viewModelName = $"{viewName}Test, {viewAssemblyName}";
                return Type.GetType(viewModelName);
            });
        }
    }
}

上面這兩句是關鍵:

".viewsb. " 表示 view 所在文件夾 namespace,".viewmodelsa.ohmygod. " 表示 viewmodel 所在 namespace

var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");

test 表示 viewmodel 後綴

var viewModelName = $"{viewName}Test, {viewAssemblyName}";
  1. 自定義 viewmodel 註冊

我們新建一個 foo 類作為自定義類,代碼如下:

using Prism.Commands;
using Prism.Mvvm;

namespace PrismSample
{
   public class Foo:BindableBase
    {

        private string _text;
        public string Text
        {
            get { return _text; }
            set { SetProperty(ref _text, value); }
        }

        public Foo()
        {
            this.Text = "Foo";
        }

        private DelegateCommand _clickCommnd;
        public DelegateCommand ClickCommnd =>
            _clickCommnd ?? (_clickCommnd = new DelegateCommand(ExecuteClickCommnd));

        void ExecuteClickCommnd()
        {
            this.Text = "Oh My God!";
        }
    }
}

修改 app.cs 代碼:

protected override void ConfigureViewModelLocator()
{
    base.ConfigureViewModelLocator();
    ViewModelLocationProvider.Register<MainWindow, Foo>();
    //ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
    //{
    //    var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
    //    var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
    //    var viewModelName = $"{viewName}Test, {viewAssemblyName}";
    //    return Type.GetType(viewModelName);
    //});
}

運行:

點擊按鈕:

就算是不注釋修改命名規則的代碼,我們發現運行結果還是一樣,因此我們可以得出結論,

這種直接的,不通過反射註冊的自定義註冊方式優先級會高點,在官方文檔也說明這種方式效率會高點

且官方提供 4 種方式,其餘三種的註冊方式如下:

ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(MainWindowTest));
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve<Foo>());
ViewModelLocationProvider.Register<MainWindow>(() => Container.Resolve<Foo>());
Keep Exploring

延伸阅读

更多文章