MvvmLight + Microsoft.Extensions.DependencyInjection + WpfApp(.NetCore3.1)
git clone MvvmLight失败,破网络, 就没有直接修改源码的方式来使用了
Nuget安装MvvmLightLibsStd10
使用GalaSoft.MvvmLight.Command命名空间下的RelayCommand会有一个Bug, CanExecute的返回不会更新UI, 在GalaSoft.MvvmLight.CommandWpf中进行了Fixed, 然而MvvmLightLibsStd10并没有GalaSoft.MvvmLight.CommandWpf, 直接粗暴的把GalaSoft.MvvmLight.CommandWpf下面的RelayCommand提到工程中
using GalaSoft.MvvmLight.Helpers;
using System;
using System.Threading;
using System.Windows.Input;
namespace TraceApp.LinkLib.Wpf.Extras
{
/// <summary>
/// A command whose sole purpose is to relay its functionality to other
/// objects by invoking delegates. The default return value for the CanExecute
/// method is 'true'. This class does not allow you to accept command parameters in the
/// Execute and CanExecute callback methods.
/// </summary>
/// <remarks>If you are using this class in WPF4.5 or above, you need to use the
/// GalaSoft.MvvmLight.CommandWpf namespace (instead of GalaSoft.MvvmLight.Command).
/// This will enable (or restore) the CommandManager class which handles
/// automatic enabling/disabling of controls based on the CanExecute delegate.</remarks>
public class RelayCommand : ICommand
{
private readonly WeakAction _execute;
private readonly WeakFunc<bool> _canExecute;
private EventHandler _requerySuggestedLocal;
/// <summary>
/// Initializes a new instance of the RelayCommand class that
/// can always execute.
/// </summary>
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
/// you must set keepTargetAlive to true to avoid side effects. </param>
/// <param name="keepTargetAlive">If true, the target of the Action will
/// be kept as a hard reference, which might cause a memory leak. You should only set this
/// parameter to true if the action is causing a closure. See
/// http://galasoft.ch/s/mvvmweakaction. </param>
/// <exception cref="T:System.ArgumentNullException">If the execute argument is null.</exception>
public RelayCommand(Action execute, bool keepTargetAlive = false)
: this(execute, (Func<bool>)null, keepTargetAlive)
{
}
/// <summary>Initializes a new instance of the RelayCommand class.</summary>
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
/// you must set keepTargetAlive to true to avoid side effects. </param>
/// <param name="canExecute">The execution status logic. IMPORTANT: If the func causes a closure,
/// you must set keepTargetAlive to true to avoid side effects. </param>
/// <param name="keepTargetAlive">If true, the target of the Action will
/// be kept as a hard reference, which might cause a memory leak. You should only set this
/// parameter to true if the action is causing a closures. See
/// http://galasoft.ch/s/mvvmweakaction. </param>
/// <exception cref="T:System.ArgumentNullException">If the execute argument is null.</exception>
public RelayCommand(Action execute, Func<bool> canExecute, bool keepTargetAlive = false)
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
this._execute = new WeakAction(execute, keepTargetAlive);
if (canExecute == null)
return;
this._canExecute = new WeakFunc<bool>(canExecute, keepTargetAlive);
}
/// <summary>
/// Occurs when changes occur that affect whether the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (this._canExecute == null)
return;
EventHandler eventHandler = this._requerySuggestedLocal;
EventHandler comparand;
do
{
comparand = eventHandler;
eventHandler = Interlocked.CompareExchange<EventHandler>(ref this._requerySuggestedLocal, comparand + value, comparand);
}
while (eventHandler != comparand);
CommandManager.RequerySuggested += value;
}
remove
{
if (this._canExecute == null)
return;
EventHandler eventHandler = this._requerySuggestedLocal;
EventHandler comparand;
do
{
comparand = eventHandler;
eventHandler = Interlocked.CompareExchange<EventHandler>(ref this._requerySuggestedLocal, comparand - value, comparand);
}
while (eventHandler != comparand);
CommandManager.RequerySuggested -= value;
}
}
/// <summary>
/// Raises the <see cref="E:GalaSoft.MvvmLight.CommandWpf.RelayCommand.CanExecuteChanged" /> event.
/// </summary>
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">This parameter will always be ignored.</param>
/// <returns>true if this command can be executed; otherwise, false.</returns>
public bool CanExecute(object parameter)
{
if (this._canExecute == null)
return true;
if (this._canExecute.IsStatic || this._canExecute.IsAlive)
return this._canExecute.Execute();
return false;
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">This parameter will always be ignored.</param>
public virtual void Execute(object parameter)
{
if (!this.CanExecute(parameter) || this._execute == null || !this._execute.IsStatic && !this._execute.IsAlive)
return;
this._execute.Execute();
}
}
/// <summary>
/// A generic command whose sole purpose is to relay its functionality to other
/// objects by invoking delegates. The default return value for the CanExecute
/// method is 'true'. This class allows you to accept command parameters in the
/// Execute and CanExecute callback methods.
/// </summary>
/// <typeparam name="T">The type of the command parameter.</typeparam>
/// <remarks>If you are using this class in WPF4.5 or above, you need to use the
/// GalaSoft.MvvmLight.CommandWpf namespace (instead of GalaSoft.MvvmLight.Command).
/// This will enable (or restore) the CommandManager class which handles
/// automatic enabling/disabling of controls based on the CanExecute delegate.</remarks>
public class RelayCommand<T> : ICommand
{
private readonly WeakAction<T> _execute;
private readonly WeakFunc<T, bool> _canExecute;
/// <summary>
/// Initializes a new instance of the RelayCommand class that
/// can always execute.
/// </summary>
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
/// you must set keepTargetAlive to true to avoid side effects. </param>
/// <param name="keepTargetAlive">If true, the target of the Action will
/// be kept as a hard reference, which might cause a memory leak. You should only set this
/// parameter to true if the action is causing a closure. See
/// http://galasoft.ch/s/mvvmweakaction. </param>
/// <exception cref="T:System.ArgumentNullException">If the execute argument is null.</exception>
public RelayCommand(Action<T> execute, bool keepTargetAlive = false)
: this(execute, (Func<T, bool>)null, keepTargetAlive)
{
}
/// <summary>Initializes a new instance of the RelayCommand class.</summary>
/// <param name="execute">The execution logic. IMPORTANT: If the action causes a closure,
/// you must set keepTargetAlive to true to avoid side effects. </param>
/// <param name="canExecute">The execution status logic. IMPORTANT: If the func causes a closure,
/// you must set keepTargetAlive to true to avoid side effects. </param>
/// <param name="keepTargetAlive">If true, the target of the Action will
/// be kept as a hard reference, which might cause a memory leak. You should only set this
/// parameter to true if the action is causing a closure. See
/// http://galasoft.ch/s/mvvmweakaction. </param>
/// <exception cref="T:System.ArgumentNullException">If the execute argument is null.</exception>
public RelayCommand(Action<T> execute, Func<T, bool> canExecute, bool keepTargetAlive = false)
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
this._execute = new WeakAction<T>(execute, keepTargetAlive);
if (canExecute == null)
return;
this._canExecute = new WeakFunc<T, bool>(canExecute, keepTargetAlive);
}
/// <summary>
/// Occurs when changes occur that affect whether the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (this._canExecute == null)
return;
CommandManager.RequerySuggested += value;
}
remove
{
if (this._canExecute == null)
return;
CommandManager.RequerySuggested -= value;
}
}
/// <summary>
/// Raises the <see cref="E:GalaSoft.MvvmLight.CommandWpf.RelayCommand`1.CanExecuteChanged" /> event.
/// </summary>
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data
/// to be passed, this object can be set to a null reference</param>
/// <returns>true if this command can be executed; otherwise, false.</returns>
public bool CanExecute(object parameter)
{
if (this._canExecute == null)
return true;
if (this._canExecute.IsStatic || this._canExecute.IsAlive)
{
if (parameter == null && typeof(T).IsValueType)
return this._canExecute.Execute(default(T));
if (parameter == null || parameter is T)
return this._canExecute.Execute((T)parameter);
}
return false;
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data
/// to be passed, this object can be set to a null reference</param>
public virtual void Execute(object parameter)
{
object parameter1 = parameter;
if (parameter != null && parameter.GetType() != typeof(T) && parameter is IConvertible)
parameter1 = Convert.ChangeType(parameter, typeof(T), (IFormatProvider)null);
if (!this.CanExecute(parameter1) || this._execute == null || !this._execute.IsStatic && !this._execute.IsAlive)
return;
if (parameter1 == null)
{
if (typeof(T).IsValueType)
this._execute.Execute(default(T));
else
this._execute.Execute(default(T));
}
else
this._execute.Execute((T)parameter1);
}
}
}
一不做二不休, 发现MvvmLightLibsStd10中也没有DispatcherHelper, 也提取出来
using System;
using System.Text;
using System.Windows.Threading;
namespace TraceApp.LinkLib.Wpf.Extras
{
/// <summary>
/// Helper class for dispatcher operations on the UI thread.
/// </summary>
public static class DispatcherHelper
{
/// <summary>
/// Gets a reference to the UI thread's dispatcher, after the
/// <see cref="M:GalaSoft.MvvmLight.Threading.DispatcherHelper.Initialize" /> method has been called on the UI thread.
/// </summary>
public static Dispatcher UIDispatcher { get; private set; }
/// <summary>
/// Executes an action on the UI thread. If this method is called
/// from the UI thread, the action is executed immendiately. If the
/// method is called from another thread, the action will be enqueued
/// on the UI thread's dispatcher and executed asynchronously.
/// <para>For additional operations on the UI thread, you can get a
/// reference to the UI thread's dispatcher thanks to the property
/// <see cref="P:GalaSoft.MvvmLight.Threading.DispatcherHelper.UIDispatcher" /></para>.
/// </summary>
/// <param name="action">The action that will be executed on the UI
/// thread.</param>
public static void CheckBeginInvokeOnUI(Action action)
{
if (action == null)
return;
DispatcherHelper.CheckDispatcher();
if (DispatcherHelper.UIDispatcher.CheckAccess())
action();
else
DispatcherHelper.UIDispatcher.BeginInvoke((Delegate)action);
}
private static void CheckDispatcher()
{
if (DispatcherHelper.UIDispatcher == null)
{
StringBuilder stringBuilder = new StringBuilder("The DispatcherHelper is not initialized.");
stringBuilder.AppendLine();
stringBuilder.Append("Call DispatcherHelper.Initialize() in the static App constructor.");
throw new InvalidOperationException(stringBuilder.ToString());
}
}
/// <summary>Invokes an action asynchronously on the UI thread.</summary>
/// <param name="action">The action that must be executed.</param>
/// <returns>An object, which is returned immediately after BeginInvoke is called, that can be used to interact
/// with the delegate as it is pending execution in the event queue.</returns>
public static DispatcherOperation RunAsync(Action action)
{
DispatcherHelper.CheckDispatcher();
return DispatcherHelper.UIDispatcher.BeginInvoke((Delegate)action);
}
/// <summary>
/// This method should be called once on the UI thread to ensure that
/// the <see cref="P:GalaSoft.MvvmLight.Threading.DispatcherHelper.UIDispatcher" /> property is initialized.
/// <para>In a Silverlight application, call this method in the
/// Application_Startup event handler, after the MainPage is constructed.</para>
/// <para>In WPF, call this method on the static App() constructor.</para>
/// </summary>
public static void Initialize()
{
if (DispatcherHelper.UIDispatcher != null && DispatcherHelper.UIDispatcher.Thread.IsAlive)
return;
DispatcherHelper.UIDispatcher = Dispatcher.CurrentDispatcher;
}
/// <summary>
/// Resets the class by deleting the <see cref="P:GalaSoft.MvvmLight.Threading.DispatcherHelper.UIDispatcher" />
/// </summary>
public static void Reset()
{
DispatcherHelper.UIDispatcher = (Dispatcher)null;
}
}
}
Nuget安装Microsoft.Extensions.DependencyInjection
创建一个类AppLocator, 在App.Xaml中申明为全局资源来做Service的注册来View的绑定
AppLocator
using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Trace.Model;
using TraceApp.DB;
using TraceApp.ViewModel;
namespace TraceApp
{
public class AppLocator
{
public IServiceProvider ServiceProvider { get; private set; }
public IConfiguration Configuration { get; private set; }
public AppLocator()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true);
Configuration = builder.Build();
var collection = new ServiceCollection();
ConfigureServices(collection);
ServiceProvider = collection.BuildServiceProvider();
}
private void ConfigureServices(IServiceCollection services)
{
// Configuration
services.Configure<AppSettings>(Configuration.GetSection(nameof(AppSettings)));
// Database
services.AddDbContext<MyContext>(options =>
{
options.UseSqlite("Data Source=TraceApp.db3");
options.UseLoggerFactory(LoggerFactory.Create(builder =>
{
builder.AddFilter((category, level) =>
category == DbLoggerCategory.Database.Command.Name
&& level == LogLevel.Information);
builder.AddConsole();
}));
});
#region Register ViewModel
services.AddSingleton<MainWindowViewModel>();
#endregion
}
#region ViewModel's DataContexts
public MainWindowViewModel MainWindow => ServiceProvider.GetService<MainWindowViewModel>();
#endregion
}
}
运行, 效果是自己想要的
附上App.Xaml、MainWindow.Xaml、MainWindowViewModel.cs的代码
App.Xaml
<Application x:Class="TraceApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TraceApp">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--Handy Control-->
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
</ResourceDictionary.MergedDictionaries>
<local:AppLocator x:Key="AppLocator"/>
</ResourceDictionary>
</Application.Resources>
</Application>
MainWindow.Xaml
<Window x:Class="TraceApp.View.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"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource AppLocator}, Path=MainWindow}"
Title="MainWindow" d:DesignHeight="500" d:DesignWidth="800">
<Grid>
<WrapPanel>
<TextBlock Text="{Binding Title}"/>
<Button Content="测试命令" Command="{Binding TestCommand}"/>
<CheckBox IsChecked="{Binding Enable, Mode=TwoWay}"/>
</WrapPanel>
</Grid>
</Window>
MainWindowViewModel
using GalaSoft.MvvmLight;
using HandyControl.Controls;
using TraceApp.LinkLib.Wpf.Extras;
namespace TraceApp.ViewModel
{
public class MainWindowViewModel : ViewModelBase
{
private string _title = "Wpf Mvvm Application";
public string Title
{
get => _title;
set => Set(ref _title, value);
}
private bool _enable = false;
public bool Enable { get => _enable; set => Set(ref _enable, value); }
public RelayCommand TestCommand => new RelayCommand(() => { MessageBox.Show("Test!"); },
() => Enable);
public MainWindowViewModel()
{
}
}
}
没有了Nuget安装MvvmLight在.NetCore中使用的Warnning, 强迫症的心情愉快了很多
MvvmLight + Microsoft.Extensions.DependencyInjection + WpfApp(.NetCore3.1)的更多相关文章
- DotNetCore跨平台~一起聊聊Microsoft.Extensions.DependencyInjection
写这篇文章的心情:激动 Microsoft.Extensions.DependencyInjection在github上同样是开源的,它在dotnetcore里被广泛的使用,比起之前的autofac, ...
- 解析 Microsoft.Extensions.DependencyInjection 2.x 版本实现
项目使用了 Microsoft.Extensions.DependencyInjection 2.x 版本,遇到第2次请求时非常高的内存占用情况,于是作了调查,本文对 3.0 版本仍然适用. 先说结论 ...
- 使用诊断工具观察 Microsoft.Extensions.DependencyInjection 2.x 版本的内存占用
目录 准备工作 大量接口与实现类的生成 elasticsearch+kibana+apm asp.net core 应用 请求与快照 Kibana 上的请求记录 请求耗时的分析 请求内存的分析 第2次 ...
- Microsoft.Extensions.DependencyInjection 之三:展开测试
目录 前文回顾 IServiceCallSite CallSiteFactory ServiceProviderEngine CompiledServiceProviderEngine Dynamic ...
- Microsoft.Extensions.DependencyInjection 之三:反射可以一战(附源代码)
目录 前文回顾 IServiceCallSite CallSiteFactory ServiceProviderEngine CompiledServiceProviderEngine Dynamic ...
- Microsoft.Extensions.DependencyInjection 之二:使用诊断工具观察内存占用
目录 准备工作 大量接口与实现类的生成 elasticsearch+kibana+apm asp.net core 应用 请求与快照 Kibana 上的请求记录 请求耗时的分析 请求内存的分析 第2次 ...
- Microsoft.Extensions.DependencyInjection 之一:解析实现
[TOC] 前言 项目使用了 Microsoft.Extensions.DependencyInjection 2.x 版本,遇到第2次请求时非常高的内存占用情况,于是作了调查,本文对 3.0 版本仍 ...
- 使用 Microsoft.Extensions.DependencyInjection 进行依赖注入
没有 Autofac DryIoc Grace LightInject Lamar Stashbox Unity Ninject 的日子,才是好日子~~~~~~~~~~ Using .NET Core ...
- Microsoft.Extensions.DependencyInjection中的Transient依赖注入关系,使用不当会造成内存泄漏
Microsoft.Extensions.DependencyInjection中(下面简称DI)的Transient依赖注入关系,表示每次DI获取一个全新的注入对象.但是使用Transient依赖注 ...
随机推荐
- ansible roles 自动化安装
例: ansible roles 自动化安装memcached 文件目录结构如下: cat memcached_role.yml - hosts: memcached remote_user: ro ...
- python学习笔记-零碎知识点
1. 绝对值 abs(-4) 结果: 4 2.
- GoF23:建造者模式
目录 概念 角色分析 实现方式 方式一 角色分析 代码编写 方式二 角色分析 代码编写 总结 优点 缺点 应用场景 建造者也抽象工厂模式的比较 建造者模式也属于创建型模式,它提供了一种创建对象的最 ...
- 基于SSM的健身房管理系统
基于SSM的健身房管理系统 The project was made in 2020-05-05~2020-05-10 谨以此片博文记录下我的第一个Java小Demo 项目展示 用户登录页 用户注册页 ...
- 一阶RC高通滤波器详解(仿真+matlab+C语言实现)
文章目录 预备知识 关于电容 HPF的推导 simulink 仿真 simulink 运行结果 matlab 实现 matlab 运行结果 C语言实现 如果本文帮到了你,帮忙点个赞: 如果本文帮到了你 ...
- 最简单的手机预览WEB移动端网页的方法
网上看了很多关于该问题的解决办法,各种各样的都有,个人也测试了一些, 最后总结出一个最简单且实用的方法. 1.安装nodejs node官网下载对应版本的nodejs,安装好了之后,在node.js执 ...
- 图数据库 Nebula Graph 是什么
图数据库(英语:Graph Database)是一个使用图结构进行语义查询的数据库.该系统的关键概念是图,形式上是点 (Node 或者 Vertex) 和边 (Edge 或者 Relationship ...
- Python3+Pycharm+PyQt5环境搭建步骤
搭建环境: 操作系统:Win10 64bit Python版本:3.7 Pycharm:社区免费版 一.Python3.7安装 下载链接:官网 https://www.python.org/downl ...
- 一句话+两张图搞定JDK1.7HashMap,剩下凑字数
JDK1.7 HashMap一探究竟 HashMap很简单,原理一看散列表,实际数组+链表;Hash找索引.索引若为null,while下一个.Hash对对碰,链表依次查.加载因子.75,剩下无脑扩数 ...
- HttpServletRequest 和 HttpServletResponse详解
用HttpServletRequest,现在整理如下,以便以后查阅 请求与响应相关的类和接口非常多,下表是主要的与请求和接口相关的类以及接口. 主要的与请求和接口相关的类及接口 方 法 说 ...