NuGet包

CommunityToolkit.Mvvm
Microsoft.Extensions.DependencyInjection

IOC

CommunityToolkit.Mvvm的NuGet包中,包含了一个IOC类:Microsoft.Toolkit.Mvvm.DependencyInjection.Ioc,该类实现了IServiceProvider接口

IOC 依赖注入

在App类中使用Microsoft.Toolkit.Mvvm.DependencyInjection.Ioc直接注册,也可以同时把注册的IServiceProvider类暴露出去。推荐直接使用IOC注册。没必要暴露App和Services。

方案一:暴露App和Services,记得引用Microsoft.Extensions.DependencyInjection,不推荐使用。

public partial class App : Application
{
    public new static App Current => (App)Application.Current;

    public IServiceProvider Services { get; }

    public App()
    {
        Services = ConfigureServices();

        Ioc.Default.ConfigureServices(Services);

        this.InitializeComponent();
    }

    private static IServiceProvider ConfigureServices()
    {
        var services = new ServiceCollection();

        services.AddSingleton<ProductsViewModel>();
        services.AddSingleton<ProductViewModel>();
        services.AddSingleton<ERPModelContainer>();

        return services.BuildServiceProvider();
    }
}

方案二:直接使用Microsoft.Toolkit.Mvvm.DependencyInjection.Ioc注册,可以使用,但推荐使用第三种。

public partial class App : Application
{

    public App()
    {
        Ioc.Default.ConfigureServices(
            new ServiceCollection()
            .AddSingleton<ProductsViewModel>()
            .AddSingleton<ProductViewModel>()
            .AddSingleton<ERPModelContainer>()
            .BuildServiceProvider());

        this.InitializeComponent();
    }

}

方案三:使用类似MVVMLight的ViewModelLocator依赖注入,推荐使用

MVVMLight使用了一个应用程序资源实例化了一个.Net类ViewModelLocator,然后通过该应用程序资源实例化类绑定到页面的DataContext中,这个方法的好处是可以在XAML中输入绑定字段时,会自动弹出绑定源的字段。

<Application x:Class="ERPApp.App" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:ERPApp" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"        
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    StartupUri="MainWindow.xaml" >
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/Fluent;Component/Themes/Generic.xaml" />
                <ResourceDictionary>
                    <vm:ViewModelLocator 
                        x:Key="Locator"
                        d:IsDataSource="True"
                        xmlns:vm="clr-namespace:ERPApp.ViewModel" />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

namespace ERPApp.ViewModel
{
    public class ViewModelLocator
    {
        /// <summary>
        /// Initializes a new instance of the ViewModelLocator class.
        /// </summary>
        public ViewModelLocator()
        {
            Ioc.Default.ConfigureServices(
                new ServiceCollection()
                .AddSingleton<ProductsViewModel>()
                .AddSingleton<ProductViewModel>()
                .AddSingleton<ERPModelContainer>()
                .BuildServiceProvider());

        }	

        public ProductsViewModel Products
        {
            get
            {
                return Ioc.Default.GetRequiredService<ProductsViewModel>();
            }
        }
		
		//Remember use Ioc.Default.GetRequiredService
        public ProductViewModel Product
        {
            get
            {
                return Ioc.Default.GetRequiredService<ProductViewModel>();
            }
        }

        public ERPModelContainer ERPModelContainer
        {
            get
            {
                return Ioc.Default.GetRequiredService<ERPModelContainer>();
            }
        }

    }
}

IOC获取对象

使用App和Services获取

public partial class ProductsView : Page
{
    public ProductsView()
    {
        InitializeComponent();

        this.DataContext = App.Current.Services.GetService<ProductsViewModel>();
        //this.DataContext = App.Current.Services.GetService(typeof(ProductsViewModel));
    }
} ## 使用IOC获取
public partial class ProductsView : Page
{
    public ProductsView()
    {
        InitializeComponent();

        this.DataContext = Ioc.Default.GetRequiredService<ProductsViewModel>();
    }
} ## 使用应用程序资源实例化类
<Page.DataContext>
    <Binding Path="Products" Source="{StaticResource Locator}"></Binding>
</Page.DataContext>

删除MVVMLight

删除以下两个NuGet包

  1. MVVMLight
  2. CommonServiceLocator

日志文件夹
日志文件夹

ViewModel

public class ProductViewModel : ObservableRecipient
{
    private Product product;
    public Product Product
    {
        get => product;
        set => SetProperty(ref product, value);
    }

    #region RelayCommand

    public RelayCommand<System.Windows.Window> OKCommand { get; private set; }

    #endregion

    public ProductViewModel()
    {
        OKCommand = new RelayCommand<System.Windows.Window>(ExecuteOK);
    }

    public void ExecuteOK(System.Windows.Window window)
    {
        window.DialogResult = true;
        window.Close();
    }
}

ServiceProvider, ServiceCollection, IServiceCollection

using Microsoft.Extensions.DependencyInjection

void Microsoft.Toolkit.Mvvm.DependencyInjection.Ioc.ConfigureServices(IServiceProvider serviceProvider)

ServiceCollection : IServiceCollection

ServiceCollectionServiceExtensions -> IServiceCollection AddSingleton<TService> (this IServiceCollection services) where TService : class

ServiceCollectionContainerBuilderExtensions -> ServiceProvider BuildServiceProvider(this IServiceCollection services)

T Microsoft.Toolkit.Mvvm.DependencyInjection.Ioc.GetRequiredService<T>() where T : class

Messenger消息

手动注册和发送消息

//注册消息
WeakReferenceMessenger.Default.Register<string>(this, OnReceive);
private void OnReceive(object recipient, string message)
{
    ReceiveMessage = message;
}

发送消息
WeakReferenceMessenger.Default.Send("Hello");

使用接口自动注册和发送消息

public class ProductViewModel : ObservableRecipient, IRecipient<String>
{
	public string ReceiveMessage { get; set; }

    public ProductViewModel()
    {
        //WeakReferenceMessenger.Default.Register<string>(this, OnReceive);
        this.IsActive = true;
    }

    public void Receive(string message)
    {
        ReceiveMessage = message;
    }
	
}

手动解除注册消息

只有手动注册时,才需要手动解除注册消息,当自动注册时,只需要通过设置IsActive为true或false,自动注册或解除消息。

this.Unloaded += (sender, e) => WeakReferenceMessenger.Default.UnregisterAll(this);

通知命令是否可以执行

//MVVMLight
this.UploadPMPPLineCommand.RaiseCanExecuteChanged();

//CommunityToolkit.Mvvm
this.UploadPMPPLineCommand.NotifyCanExecuteChanged();

背景线程更新UI

Application.Current.Dispatcher.Invoke(() =>
{
    this.WebSocketConnectCommand.NotifyCanExecuteChanged();
    this.WebSocketCloseCommand.NotifyCanExecuteChanged();
});

WPF设计时绑定[Binding时提供智能提示]

在做WPF过程中,编写前端UI时,如果还没有对接数据来源,可能无法很直观的看见页面呈现效果,设计窗口也无法呈现直观的设计效果,又或者在绑定时VS无法给予属性提示等,那么设计时绑定就可以比较友好的解决这一点。

设计时绑定与运行时(普通)绑定区别

| 类别 | 运行时(普通)绑定 | 设计时绑定 | |:———–|:———–|:———–| | 编写Binding时是否有提示 | N | Y | | 设计界面时是否能看见数据展示效果 | N | Y | | 两种绑定是否可以同事兼容 | Y | Y |

命名空间

xmlns:d=”http://schemas.microsoft.com/expression/blend/2008”

设计时数据上下文

d:DataContext=”{x:Static local:DesignInstance.designStudent}”