1

我刚刚在 C# 控制台应用程序中完成了一个基本的观察者模式。它是一个基本的服务器客户端应用程序,我在其中使用了观察者模式。现在我想将它与一个 winform 应用程序集成。winform上有一个按钮。每次服务器接收到消息时,按钮都必须改变颜色或其他效果。所以基本上我希望控制台应用程序与 winform 交互。所以现在我想在这里使用观察者模式。每当服务器接收到消息时,它都会通知 winform 中的按钮,并且作为观察者的按钮会更改其颜色或闪烁或类似效果。

任何建议都会非常有帮助

问候

4

1 回答 1

4

您的问题实际上是让您的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.WParamandMessage.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;
    } 
}
于 2013-08-06T10:57:32.587 回答