WPF運(yùn)行時(shí)替換方法實(shí)現(xiàn)mvvm自動(dòng)觸發(fā)刷新
前言
我們知道,使用wpf的綁定功能,代碼觸發(fā)界面改變時(shí)需要在屬性的setter觸發(fā)PropertyChanged事件,以達(dá)到界面刷新的效果。上一章我們簡(jiǎn)化了觸發(fā)流程,但是依然需要在每個(gè)屬性的setter中調(diào)用方法。本章將再進(jìn)一步簡(jiǎn)化,實(shí)現(xiàn)setter不需要調(diào)方法就可以自動(dòng)觸發(fā)界面刷新。
一、如何實(shí)現(xiàn)
1、反射獲取屬性
通過反射獲取類的所有公有屬性
var propertyInfos = type.GetProperties(bindingAttr: BindingFlags.Instance | BindingFlags.Public);
2、定義替換方法
定義的用于替換屬性setter的方法,確保參數(shù)類型兼容。設(shè)置NoInlining確保不會(huì)被內(nèi)聯(lián)優(yōu)化失去函數(shù)地址。再方法中觸發(fā)RaisePropertyChangedEvent。
[MethodImpl(MethodImplOptions.NoInlining)]
void Setter0_obj(object value) {
//此時(shí)Setter0_obj已經(jīng)被替換成了屬性的setter,調(diào)用會(huì)進(jìn)入屬性的setter中。
Setter0_obj(value);
RaisePropertyChangedEvent(_propertyInfos![0].Name); }
3、交換屬性的setter方法
將定義的替換方法與屬性的setter交換。MethodHooker.SwapMethod可以去搜索C#運(yùn)行時(shí)替換函數(shù)的方法,本章的只是去掉了unsafe的實(shí)現(xiàn)。
var oldSetter = propertyInfos[i].GetSetMethod();
if (oldSetter != null && oldSetter.IsPublic)
//定義了set且set為公有時(shí)才交換。
{
MethodInfo newSetter= type.BaseType.GetMethod("Setter0_obj", BindingFlags.Instance | BindingFlags.NonPublic)!;
MethodHooker.SwapMethod(oldSetter, newSetter);
}
二、完整代碼
1、接口
/// <summary>
/// ViewModelBase,繼承此類可以簡(jiǎn)化屬性的定義,不需要手動(dòng)觸發(fā)RaisePropertyChangedEvent。
/// 用法:繼承此類,屬性為公有,set為公有且非內(nèi)聯(lián),設(shè)置屬性就會(huì)自動(dòng)觸發(fā)mvvm的binding。
/// 實(shí)驗(yàn)性質(zhì),其他.net版本無效,在.net6.0是穩(wěn)定的,。x64、x86,debug和release都可以使用。release需要給set設(shè)置[MethodImpl(MethodImplOptions.NoInlining)],否則無法實(shí)現(xiàn)函數(shù)交換。
/// 目前支持64個(gè)屬性,單個(gè)屬性(struct)最大128字節(jié),需要更多可以自行調(diào)用GenSetters生成代碼。
/// </summary>
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ViewModelBase();
//依然提供此方法用于手動(dòng)觸發(fā)
protected void RaisePropertyChangedEvent([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "");
}
2、項(xiàng)目
vs2022 .net 6.0項(xiàng)目。
注:目前版本只能在.net6.0中正常使用,x64、x86、debug、release都沒問題。其他.net版本大概率無效果或者異常。
三、使用示例
倒計(jì)時(shí)
(1)繼承ViewModelBase
public class TimeTick : ViewModelBase
(2)定義屬性
set為公有,以及[MethodImpl(MethodImplOptions.NoInlining)]避免內(nèi)聯(lián)。支持非缺省set方法體,即可以在set中加入一些邏輯。
public class TimeTick : ViewModelBase
{
public double Seconds { get; [MethodImpl(MethodImplOptions.NoInlining)] set; }=60;
}
(3)屬性賦值
public TimeTick()
{
var time = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(1000) };
time.Tick += (s, e) =>Seconds--;
time.Start();
}
(4)窗口關(guān)聯(lián)ViewModel
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new TimeTick();
}
}
(5)xaml綁定
<TextBlock Text="{Binding Seconds}" />
效果預(yù)覽

總結(jié)
替換函數(shù)原理很簡(jiǎn)單,但是具體實(shí)現(xiàn)還是比較麻煩的,尤其是需要適配不同的.net版本,本文目前只支持.net6.0。還有就是函數(shù)的參數(shù),引用和值類型的區(qū)分,以及值類型的傳值兼容,這些都是通過多次嘗試才找個(gè)合理的方式。通過本文簡(jiǎn)化的ViewModelBase使用變的非常方便了,除了需要給set添加非內(nèi)聯(lián)屬性,其他已經(jīng)和普通屬性沒有區(qū)別。
到此這篇關(guān)于WPF運(yùn)行時(shí)替換方法實(shí)現(xiàn)mvvm自動(dòng)觸發(fā)刷新的文章就介紹到這了,更多相關(guān)WPF mvvm自動(dòng)觸發(fā)刷新內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解析C#設(shè)計(jì)模式編程中備忘錄模式的運(yùn)用
這篇文章主要介紹了C#設(shè)計(jì)模式編程中備忘錄模式的運(yùn)用,備忘錄模式用來保存與對(duì)象有關(guān)的數(shù)據(jù)用以在將來對(duì)對(duì)象進(jìn)行復(fù)原,需要的朋友可以參考下2016-02-02
C#實(shí)現(xiàn)身份證驗(yàn)證功能的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)身份證驗(yàn)證功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12
c# n個(gè)數(shù)排序?qū)崿F(xiàn)代碼
c# n個(gè)數(shù)排序?qū)崿F(xiàn)代2009-07-07
在C# WPF項(xiàng)目中集成PDF查看器的兩種方法
文章介紹了在WPF中使用PdfiumViewer控件的兩種方法:通過NuGet包安裝并手動(dòng)創(chuàng)建控件,創(chuàng)建自定義WPF控件,文章還解決了在WPF中使用PdfiumViewer時(shí)可能出現(xiàn)的常見問題,需要的朋友可以參考下2025-12-12
c# 兩個(gè)數(shù)組比較,將重復(fù)部分去掉,返回不重復(fù)部分的實(shí)現(xiàn)
下面小編就為大家?guī)硪黄猚# 兩個(gè)數(shù)組比較,將重復(fù)部分去掉,返回不重復(fù)部分的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12
c#通過反射實(shí)現(xiàn)對(duì)象自動(dòng)映射的實(shí)現(xiàn)
本文主要介紹了c#通過反射完成對(duì)象自動(dòng)映射的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02
C#使用泛型方法實(shí)現(xiàn)操作不同數(shù)據(jù)類型的數(shù)組
這篇文章主要為大家詳細(xì)介紹了C#如何使用一個(gè)泛型方法對(duì)不同類型的數(shù)組進(jìn)行操作,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下2024-02-02

