在基于Prism的MVVM架构中,用到了Socket通信作为Server。SocketClass类定义了单例模式,然后在软件启动的时候,就加载SocketClass并一直监听Client的消息。该消息包行了不同的标志,根据标志值加载不同类的方法。也就是加载View.xaml对应的ViewModel.cs。
那么问题来了,如何加载其他类(ViewModel.cs)的方法呢?用委托就可以解决。
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/using-delegates
委托:一个类调用另个类的方法。相当于调用一个方法体。
回调:用委托调用一个类的方法后,再返回该方法。相当于返回一个方法体。回调是从你的线程上开始执行的,回调即一个对象将一个方法的引用(方法的引用用委托保存)传入另一个对象,使得只有他能返回信息,这就是一个回调。
https://blog.csdn.net/falcomavin/article/details/72882939
https://blog.csdn.net/huang9012/article/details/38753305
https://www.cnblogs.com/kudsu/p/7722334.html(委托,重点)
https://www.jb51.net/article/98976.htm(委托+回调)
https://www.cnblogs.com/yangfengwu/p/5761841.html(委托+回调)
https://www.cnblogs.com/joy99/p/7354233.html
主程序
#region 委托
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using test;
namespace QueueSample
{
class Program
{
public delegate int MethodDelegate(int x, int y);
public delegate int MyDel(int name);
private static MethodDelegate method;
static void Main(string[] args)
{
/*一、委托只调用一个静态方法*/
Console.WriteLine("一、委托只调用一个静态方法");
method = new MethodDelegate(DelegateClass.Add);
int aa = method(10, 20);
Console.WriteLine(method(10, 20));
/*二、委托同时调用两个静态方法*/
Console.WriteLine("二、委托同时调用两个静态方法");
var add = new MyDel(DelegateClass.Add1);
add += new MyDel(DelegateClass.Add2);//多播委托:委托重载Add2方法。相当于一个委托可以加载多个方法。
add(10);
//Console.WriteLine(add(10));
Console.ReadLine();
}
}
}
#endregion
委托的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test
{
public class DelegateMethon
{
static int a = 0;
static int b = 0;
public static int Add(int x, int y)
{
a = x;
b = y;
return x + y;
}
public static int Add1(int a)
{
var b = 10 + a;
Console.WriteLine(b);
return b;
}
public static int Add2(int a)
{
var b = 10 - a;
Console.WriteLine(b);
return b;
}
}
}
请看上面博客链接。
https://www.cnblogs.com/kudsu/p/7722334.html(委托,重点)
https://www.jb51.net/article/98976.htm(委托+回调)
https://www.cnblogs.com/yangfengwu/p/5761841.html(委托+回调)
http://www.cnblogs.com/sunfom/p/8145066.html
参考下面的博客,写一个例子
https://blog.csdn.net/qq_36927190/article/details/79330171
#region 委托\回调
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using test;
namespace QueueSample
{
class Program
{
public delegate int MethodDelegate(int x, int y);
public delegate int MyDel(int name);
private static MethodDelegate method;
public delegate void MethodDelegateA(int x, int y);
private static MethodDelegateA methodA;
static void Main(string[] args)
{
/*一、委托只调用一个静态方法*/
Console.WriteLine("一、委托只调用一个静态方法");
method = new MethodDelegate(DelegateMethon.Add);
int aa = method(10, 20);
Console.WriteLine(method(10, 20));
methodA = new MethodDelegateA(DelegateMethon.Add3);
methodA(11, 99);
/*二、委托同时调用两个静态方法*/
Console.WriteLine("二、委托同时调用两个静态方法");
var add = new MyDel(DelegateMethon.Add1);
add += new MyDel(DelegateMethon.Add2);//多播委托:委托重载Add2方法。相当于一个委托可以加载多个方法。
add(10);
/*三、回调函数1:*/
Console.WriteLine("三、回调函数1:");
CallBackClasss c = new CallBackClasss();
c.TestCallBack(PublicFunc.CallBack);
Console.ReadLine();
}
}
}
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace test
{
public class CallBackClasss
{
public void TestCallBack(Action what)
{
Console.WriteLine("开始");
Thread.Sleep(2000);
what("233");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test
{
public class PublicFunc
{
public static void CallBack(string s)
{
Console.WriteLine(s);
Console.ReadLine();
}
}
}
参考别人的项目,用到了回调函数,一直不明白,现在把它解剖出来。
public StudyPage()
{
InitializeComponent();
m_cStudyEventProc.m_cKrayGenDll.SetDRUIUpdate(DRGenUpdateUIFun);
}
DRGenUpdateUIFun是函数的SetDRUIUpdate实参,以后委托的指针就指向了DRGenUpdateUIFun实参了。 这步骤,我们先不讨论这个实现是什么东西。我我们先看函数SetDRUIUpdate()。
///
///功能描述:设置DR回调更新UI功能函数
///参数:无
///返回值: 无
///
public void SetDRUIUpdate(DRInfoDelegate ICallBack)
{
m_fDRUpdateUIInfo = ICallBack;
}
形参ICallBack,就是一个委托DRInfoDelegate。实际上,SetDRUIUpdate函数的参数,传递了一个委托进来。于是,我们需要找到这个DRInfoDelegate是什么东西?
//UI更新委托函数
public delegate void DRInfoDelegate(int nCmd, int nVal);
private DRInfoDelegate m_fDRUpdateUIInfo = null;
到了这里,你就会明白。DRInfoDelegate传入两个参数,返回值Void。此外,你不经要问,m_fDRUpdateUIInfo 明明等于null,我们到底在哪实例化这个委托对象m_fDRUpdateUIInfo呢?
你再仔细看看,m_fDRUpdateUIInfo在第一步的SetDRUIUpdate函数中,赋值了。绕来绕去,妈的,我现在重新理解一下SetDRUIUpdate这个函数。这个函数的功能就是,为委托变量m_fDRUpdateUIInfo赋值一个委托形参ICallBack。
m_fDRUpdateUIInfo委托指向或者说调用 ICallBack委托。相当于连个委托指向同一个地址。
指向了DRGenUpdateUIFun方法。
///
///功能描述: 通知更新功能函数
///参数:nCmd 消息命令
/// nVal 值
///返回值: 无
///
private void DRGenUpdateUIFun(int nCmd, int nVal)
{
this.Dispatcher.Invoke(new GenUpdateDRDataDelegate(UpdateGenDRFunProc), new object[] { nCmd, nVal });
}
DRGenUpdateUIFun方法,会执行GenUpdateDRDataDelegate这个委托下的UpdateGenDRFunProc方法。
GenUpdateDRDataDelegate委托:
private delegate void GenUpdateDRDataDelegate(int Cmd, int Val);
UpdateGenDRFunProc方法:
///
///功能描述: 处理高压DR模式返回消息更新UI功能函数
///参数:nCmd 消息命令
/// nVal 值
///返回值: 无
///
private void UpdateGenDRFunProc(int nCmd, int nVal)
{
double fMa;
double fMs;
double fMas;
switch (nCmd)
{
case KrayGenDll.GEN_EM_MSG: //摄影模式
SetEMValue(nVal);
break;
case KrayGenDll.GEN_KV_MSG: //普通摄影Kv值
m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- DR-KV=" + Convert.ToString(nVal));
m_cGlobalData.m_StudyDicomTag.nKv = (ushort)nVal;
m_cGenFeedBack.DR_KV = nVal;
m_cGlobalData.m_cTaurenComm.SetKvToOTC(nVal);
break;
case KrayGenDll.GEN_MA_MSG: //普通摄影Ma值
m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- DR-MA=" + Convert.ToString(nVal));
fMa = Math.Round(nVal / 10.0f, 1);//保留一位小数
m_cGlobalData.m_StudyDicomTag.fMa = (float)fMa;
m_cGenFeedBack.DR_MA = (float)fMa;
m_cGlobalData.m_cTaurenComm.SetMaToOTC((float)fMa);
break;
case KrayGenDll.GEN_MS_MSG: //普通摄影Ms值
m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- DR-MS=" + Convert.ToString(nVal));
fMs = Math.Round(nVal / 100.0f, 1);
m_cGlobalData.m_StudyDicomTag.nMs = (ushort)fMs;
m_cGenFeedBack.DR_MS = (float)fMs;
m_cGlobalData.m_cTaurenComm.SetMsToOTC((float)fMs);
break;
case KrayGenDll.GEN_MX_MSG: //普通摄影Mas值
fMas = Math.Round(nVal / 1000.0f, 1);
m_cGlobalData.m_StudyDicomTag.fMas = (float)fMas;
m_cGenFeedBack.DR_MX = (float)fMas;
m_cGlobalData.m_cTaurenComm.SetMasToOTC((float)fMas);
break;
case KrayGenDll.GEN_FO_MSG: //普通摄影焦点值
m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- GenFocus=" + Convert.ToString(nVal));
SetGenFocusUI(nVal);
break;
case KrayGenDll.GEN_AECFN_MSG: //AEC模式密度值
break;
case KrayGenDll.GEN_AECFI_MSG: //AEC场值
m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- AecCFI=" + Convert.ToString(nVal));
SetAecFieldStatus(nVal);
break;
case KrayGenDll.GEN_AECFS_MSG: //AEC屏速值
break;
case KrayGenDll.GEN_AECAT_MSG: //AEC实际曝光时间值
break;
case KrayGenDll.GEN_TE_MSG: //摄影技术值(0:MA-MS曝光 1:MAS曝光 2:AEC曝光)
SetExpTechModeUI(nVal);
m_cStudyEventProc.m_nExpTechMode = nVal;
break;
case KrayGenDll.GEN_ELERROR_MSG:
m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- Error:EL" + Convert.ToString(nVal));
RayImageErrorCode.AppearErrorInfo(nVal);
break;
case KrayGenDll.GEN_ERERROR_MSG:
m_cGlobalData.m_cLogs.WriteDebugLog("DRGenUpdateUIFun-- Error:ER" + Convert.ToString(nVal));
RayImageErrorCode.AppearErrorInfo(nVal);
break;
case KrayGenDll.GEN_INIT_MSG:
GenGeneralError.AppearErrorInfo(nVal,"");
break;
case KrayGenDll.GEN_CLEARERROR_MSG:
RayImageErrorCode.RemoveErrorInfo();
break;
case KrayGenDll.GEN_KEEPLIVE_MSG: //高压断开通讯
GenGeneralError.AppearErrorInfo(5, "");
break;
case KrayGenDll.GEN_LOAD_MSG://高压加载状态消息
GenGeneralError.AppearErrorInfo(1, "");
break;
default:
break;
}
}
以上几个步骤,我们知道了m_fDRUpdateUIInfo委托最后指向了形参ICallBack委托所执行的函数 UpdateGenDRFunProc(int nCmd, int nVal),也就是说m_fDRUpdateUIInfo会执行函数 UpdateGenDRFunProc(int nCmd, int nVal)。
这个时候,我们用m_fDRUpdateUIInfo(nCmd,nVal)委托,就能将参数传递给UpdateGenDRFunProc(int nCmd, int nVal)函数,并执行该函数。
说白了,m_fDRUpdateUIInfo(nCmd,nVal)委托就是指向了UpdateGenDRFunProc(int nCmd, int nVal)函数的地址。
委托m_fDRUpdateUIInfo—指向—> 委托形参ICallBack—指向—>SetDRUIUpdate的实参DRGenUpdateUIFun。最后,委托就是指向了实参的地址。