winforms和控制台应用程序以及观察者设计模式之间的交互

时间:2013-08-06 09:20:02

标签: c# winforms visual-studio-2010 console observer-pattern

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

任何建议都会非常有用

此致

1 个答案:

答案 0 :(得分:3)

您的问题实际上是允许您的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,可以将其从此发送到双方。我正在尝试通过Message.WParamMessage.LParam指针将此数据发送到该数据。然而,这并不容易。不同的进程具有受保护的不同内存块。

我使用FindWindow查找winforms window,但并非总是如此(可能有一些其他窗口具有相同的标题)。然而,这只是为了示范目的,它不完整,它只是一个演示。您可以搜索如何找到确切的窗口(它不是太复杂,只需要使用更多代码)。

如果要在窗口之间发送任意数据,可以尝试其他IPC方法。如果我可以改进此答案(以便我们可以将Console中的任意颜色发送到您的winforms),我会稍后更新。

更新

上述解决方案非常适合简单的要求,它只发送自定义消息来表示发送方希望接收方做什么。但是,要发送任意数据,您必须发送消息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;
    }    

Winforms代码:

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;
    } 
}