我刚刚在 C# 控制台应用程序中完成了一个基本的观察者模式。它是一个基本的服务器客户端应用程序,我在其中使用了观察者模式。现在我想将它与一个 winform 应用程序集成。winform上有一个按钮。每次服务器接收到消息时,按钮都必须改变颜色或其他效果。所以基本上我希望控制台应用程序与 winform 交互。所以现在我想在这里使用观察者模式。每当服务器接收到消息时,它都会通知 winform 中的按钮,并且作为观察者的按钮会更改其颜色或闪烁或类似效果。
任何建议都会非常有帮助
问候
我刚刚在 C# 控制台应用程序中完成了一个基本的观察者模式。它是一个基本的服务器客户端应用程序,我在其中使用了观察者模式。现在我想将它与一个 winform 应用程序集成。winform上有一个按钮。每次服务器接收到消息时,按钮都必须改变颜色或其他效果。所以基本上我希望控制台应用程序与 winform 交互。所以现在我想在这里使用观察者模式。每当服务器接收到消息时,它都会通知 winform 中的按钮,并且作为观察者的按钮会更改其颜色或闪烁或类似效果。
任何建议都会非常有帮助
问候
您的问题实际上是让您的Console
应用程序控制Winforms
应用程序。所以为了简单起见,我做了这个演示,很容易实现你自己的方式:
您的Console
应用程序代码:
//Must add reference to System.Drawing.dll
//using namespaces:
using System.Runtime.InteropServices;
using System.Drawing;
//..........................
class Program {
//This is used to send custom message to your Winforms
[DllImport("user32")]
private static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
//This is used to find your winforms window
[DllImport("user32", CharSet=CharSet.Auto)]
private static extern IntPtr FindWindow(string className, string windowName);
//This is used to register custom message so that it's ensured to be unique
[DllImport("user32")]
private static extern int RegisterWindowMessage(string msgName);
//Our main method
static void Main(string[] args)
{
int red = RegisterColorCode(Color.Red);
int yellow = RegisterColorCode(Color.Yellow);
while (true)
{
Console.Write("Enter color letter: ");
string r = Console.ReadLine().ToLower();
int msg = 0;
if(r == "r") msg = red;
if(r == "y") msg = yellow;
//You can define more colors
if (hwnd == IntPtr.Zero)
hwnd = FindWindow(null, "Winforms Application");
if(hwnd != IntPtr.Zero) SetBackColor(msg);
}
}
IntPtr hwnd = IntPtr.Zero;
static int RegisterColorCode(Color c){
return RegisterWindowMessage(c.ToString());
}
static void SetBackColor(int colorCode){
SendMessage(hwnd, colorCode, IntPtr.Zero, IntPtr.Zero);
}
}
您的Winforms
应用程序代码:
public class Form1 : Form {
[DllImport("user32")]
private static extern int RegisterWindowMessage(string msgName);
public Form1(){
InitializeComponent();
red = RegisterColorCode(Color.Red);
yellow = RegisterColorCode(Color.Yellow);
//Set your form caption to a specified (must be unique at the time it runs)
Text = "Winforms Application";
}
int red,yellow;//you can define more
private int RegisterColorCode(Color c){
return RegisterWindowMessage(c.ToString());
}
protected override void WndProc(ref Message m)
{
switch(m.Msg){
case red:
yourButton.BackColor = Color.Red;
return;
case yellow:
yourButton.BackColor = Color.Yellow;
return;
}
base.WndProc(ref m);
}
}
这是一个非常简单的应用程序模型,它用于Message
与其他窗口进行通信。但是它有一些限制。如您所见,我们必须定义certain Color codes
双方可以从 this 发送到 that。我正在尝试通过Message.WParam
andMessage.LParam
指针将任何数据从这里发送到那里。然而,这并不容易。不同的进程有不同的受保护的内存块。
我FindWindow
用来查找winforms window
,这并不总是正确的(可能有一些其他窗口具有相同的标题)。然而它只是为了演示目的,它并不完整,它只是一个演示。您可以搜索如何找到确切的窗口(它不是太复杂,只是更多的代码可以使用)。
如果您想在窗口之间发送任意数据,您可以尝试其他IPC
方法。如果我可以改进这个答案(以便我们可以将任意颜色发送Console
到您的winforms
),我会稍后更新。
上面的解决方案非常适合简单的需求,它只是发送自定义消息来表明发送者希望接收者做什么。但是,要发送任意数据,您必须发送 message WM_COPYDATA = 0x4a
。有一个结构,COPYDATASTRUCT
其中包含要发送的数据和一些代码来识别发送者希望接收者做什么。这是给你的演示:
控制台代码:
class Program
{
[DllImport("user32")]
private static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
[DllImport("user32", CharSet=CharSet.Auto)]
private static extern IntPtr FindWindow(string className, string windowName);
static void Main(string[] args)
{
IntPtr hwnd = IntPtr.Zero;
while (true)
{
//require entering 3 elements of a Color: RED GREEN BLUE (each one is maximum at 255 and minimum at 0
Console.Write("Enter color R G B: ");//should enter something like 100 200 50
string[] s = Console.ReadLine().Split(new string[]{" "}, StringSplitOptions.RemoveEmptyEntries);
Color colorToBeSent = Color.FromArgb(int.Parse(s[0]),int.Parse(s[1]), int.Parse(s[2]));
COPYDATASTRUCT data = new COPYDATASTRUCT();
try
{
data.dwData = new IntPtr(123456);
data.cbSize = Marshal.SizeOf(typeof(Color));
data.lpData = Marshal.AllocHGlobal(data.cbSize);
Marshal.StructureToPtr(colorToBeSent, data.lpData, true);
if (hwnd == IntPtr.Zero)
hwnd = FindWindow(null, "Winforms Application");
if (hwnd != IntPtr.Zero)
{
SendMessage(hwnd, 0x4a, IntPtr.Zero, ref data);
}
}
finally
{
Marshal.FreeHGlobal(data.lpData);
}
}
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbSize;
public IntPtr lpData;
}
Winform 代码:
public class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void WndProc(ref Message m){
if(m.Msg == 0x4a)//WM_COPYDATA
{
COPYDATASTRUCT data = (COPYDATASTRUCT) m.GetLParam(typeof(COPYDATASTRUCT));
if (data.dwData.ToInt32() == 123456)//Check if this is sent from your Console
{
Color c = (Color)Marshal.PtrToStructure(data.lpData, typeof(Color));
yourButton.BackColor = c;
return;
}
}
base.WndProc(ref m);
}
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbSize;
public IntPtr lpData;
}
}