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依赖注 ...
随机推荐
- SQL 文件导入数据库
1.首先通过 xshell 连接数据库服务器,执行命令 mysql -u root -p 命令,按照提示输入密码,连接上数据库 2.在连接终端上执行命令 create database JD_Mode ...
- Git 上传本地项目到远程仓库 (工具篇)
前言:前面一开始写了一篇通过命令来操作本地项目上传远程仓库的文章,后来发现此方式没有那么灵活.故跟开发同事请教了下,知道了通过工具来操作更方便.所以写了这篇文章来分享&记录. 前提条件:本地安 ...
- win10 手动安装mysql-8.0.11-winx64.zip
0.彻底删除win10上安装的mysql(转载 : https://www.cnblogs.com/jpfss/p/6652701.html) 1.去官网下载mysql-8.0.11-winx64.z ...
- 1年之后的拿高工资的资本,Java线程
只要开启线程,都会开启一块对应的栈内存,然后进行同步执行. -- 谈斌 线程是CPU用来处理程序的资源,线程的执行是抢占式的. 线程开启方式: 创建一个类,继承Thread类.重写 run(), 并在 ...
- mybatis的关系映射
一.多对一的映射关系 举例:根据员工编号查询员工所在部门的部门信息 第一步,需要在多的一方也就是员工实体类中持有一的一方部门实体类的引用 第二步,在dao接口中声明方法 第三步,在mapper中实现该 ...
- Web前端基础第一天
Web标准的构成 结构:结构对于网页元素进行整理和分类,现阶段主要学的是html 表现:表现用于设置元素的板式.颜色.大小等外观样式,主要指的是CSS 行为:行为是指网页模型的定义及交互的编写,现阶段 ...
- ubuntu18.04下mysql安装时没有出现密码提示
前言: 一:配置 ubuntu 18.04 mysql 5.7.30 二:问题 ubuntu18.04下mysql安装时没有出现密码提示,安装后自己有一个默认的用户名以及密码 解决方案: 1. 在终端 ...
- dumpsys-package
dumpsys-package ams和pms是android系统最重要的系统服务,本文解析dumpsys package命令,看哪些PMS相关的系统信息,数据结构是运行时可以查看的. 命令提示 co ...
- [hdu5247]rmq+预处理
题意:有一个无序数组,求有多少个长度为k的区间满足把区间内的数排序后是连续的. 思路:长度为k的区间排序后是 连续的数等价于maxval-minval等于k-1并且不同的数有k个(或者说没有相同的数) ...
- [hdu5249]动态中位数
题意:3种操作分别为入队,出队,查询当前队列的中位数.操作数为1e5数量级. 思路:先考虑离线算法,可以离散+线段树,可以划分树,考虑在线算法,则有treap名次树,SBtree(size balan ...