2011-10-28 9 views
14

Hãy để tôi cung cấp cho bạn thông tin cơ bản.Buộc đóng MessageBox lập trình

Chúng tôi có một Ứng dụng (kích thước trung bình) đang sử dụng MessageBox.Show (....) tại các địa điểm khác nhau (trong hàng trăm).

Các hộp thư này là một phần của worklfow và được sử dụng để thông báo, cảnh báo hoặc lấy dữ liệu nhập từ người dùng. Ứng dụng được cho là tự động đăng xuất sau một thời gian nhất định nếu không có hoạt động nào. Chúng tôi có yêu cầu rằng khi đăng xuất ứng dụng, chỉ để làm sạch dữ liệu phiên, để xóa các chế độ xem và ẩn chính nó để trong lần khởi chạy tiếp theo, nó sẽ không phải thực thi quy trình khởi động tốn kém về mặt thời gian.

Mọi thứ đều hoạt động tốt nhưng trong trường hợp có một số hộp tin nhắn trên màn hình và người dùng rời khỏi máy mà không trả lời hộp tin nhắn và sau đó không có hoạt động nào để đăng ký. Vấn đề là hộp tin nhắn sẽ không biến mất.

Làm cách nào để đóng hộp thư đã mở, nếu có, trong khi ẩn ứng dụng?

Cảm ơn.

+0

lẽ gửi chìa khóa nhập hoặc esc? :) – Reniuz

+0

Tôi nghĩ 'MessageBox.Show (...)' là phương thức, vậy chương trình có thể gửi một khóa như thế nào? Bạn đang sử dụng các chủ đề/nhiệm vụ? – Fischermaen

+0

Cảm ơn bạn đã trả lời. Chỉ cần làm rõ bằng cách sử dụng hộp msg tùy chỉnh không phải là một lựa chọn như rework là khá lớn. Việc gửi khóa ESC cũng không chính xác vì chỉ ứng dụng đang hoạt động mới nhận được lệnh. Tôi đang sử dụng cách tiếp cận FIndWindow nơi tôi nhận được xử lý Msgbox bằng cách đi qua id và chú thích hộp msg. Sau khi nhận được trình xử lý, tôi đang đóng bằng cách sử dụng API win32 sau, ví dụ: SendMessage (mới HandleRef (null, msgbxcHandler), WM_CLOSE, IntPtr.Zero, IntPtr.Zero); SendMessage (mới HandleRef (null, msgbxcHandler), WM_NCDESTROY, IntPtr.Zero, IntPtr.Zero); Cho đến nay nó làm việc tốt. – NYK

Trả lời

1

Giả sử bạn có thể chỉnh sửa mã đang gọi phương thức MessageBox.Show(), tôi khuyên bạn không nên sử dụng MessageBox. Thay vào đó, chỉ cần sử dụng biểu mẫu tùy chỉnh của riêng bạn, gọi số ShowDialog() trên đó để làm cơ bản giống với lớp MessageBox. Sau đó, bạn có bản sao của biểu mẫu và bạn có thể gọi Close() vào ví dụ để đóng nó.

Ví dụ tốt là here.

+0

Ouch. Và chúng ta thấy rất nhiều lần nó khủng khiếp như thế nào khi mọi người reimplement hộp tin nhắn. 'msg' cho thấy rằng bạn có thể có một hộp tin nhắn thực sự và đóng nó sau một sự chậm trễ ... – Joey

+0

@ Joe: vâng, bạn nói đúng ... đó chỉ là một ý tưởng, không phải là tốt nhất có thể. Bạn nói _msg cho thấy rằng bạn có thể có một hộp tin nhắn thực sự và đóng nó sau khi một delay_ ... những gì hoặc ai là "msg"? Xin lỗi, tôi không hiểu, tôi cầu xin sự tha thứ của bạn – Marco

3

Câu hỏi đầu tiên: Nếu hộp thư được sử dụng như là một phần của quy trình làm việc, sẽ không đóng hộp tin nhắn theo chương trình khiến luồng thay đổi/tiếp tục?

Tôi nghĩ rằng bạn có ba tùy chọn

  1. Tạo phiên bản của riêng bạn của lớp MessageBox mở ra một cửa sổ hộp thoại trông giống như một bảng thông báo với tính năng bổ sung để nó đóng cửa tự động sau một khoảng thời gian.

  2. Thực hiện điều gì đó như thế này trong C# để đóng các hộp tin nhắn theo chương trình. http://www.codeproject.com/KB/dialog/AutoCloseMessageBox.aspx

  3. Loại bỏ các hộp thư khỏi làm gián đoạn luồng công việc. Đây có lẽ là giải pháp tốt nhất là từ âm thanh của nó đóng một hộp thông báo lập trình sẽ gây ra công việc để tiếp tục/thay đổi, và thậm chí có thể gây ra một hộp thư khác để hiển thị mà có thể không được mong muốn. Nhưng rõ ràng việc sửa chữa vấn đề gốc có thể là tốt nhất, nhưng không phải lúc nào cũng dễ dàng nhất.

1 và 2 sẽ cần phải được thực hiện từ một chuỗi riêng biệt, vì vậy bạn sẽ cần phải suy nghĩ về tác động của việc hiển thị hộp thư sẽ bị chặn.

+0

+1 cho điểm 3.! Tôi cũng sẽ không có cảm giác tốt khi "xác nhận" bất kỳ hộp thư đang mở nào mà không biết liệu người dùng có nhận thấy điều đó không ... – MartinStettner

1

Tôi nghĩ rằng cách sạch sẽ để thực hiện bạn dưới dạng hộp thông báo riêng như

class MyMessageBox : Form { 
    private MyMessageBox currentForm; // The currently active message box 

    public static Show(....) { // same as MessageBox.Show 
    // ... 
    } 

    public static Show(...) { // define additional overloads 
    } 

    public static CloseCurrent() { 
    if (currentForm != null) 
     currentForm.Close(); 
    } 

    // ... 
} 

Trong một số dự án lớn hơn của tôi, tôi thấy phương pháp này rất hữu ích cũng cho các mục đích khác (như khai thác gỗ tự động thông báo lỗi vv)

Ý tưởng thứ hai tôi sẽ sử dụng GetTopWindow() (hoặc có thể một số chức năng WIN32 khác) để có được cửa sổ cấp cao nhất hiện tại của ứng dụng và gửi thông báo WM_CLOSE cho nó.

+0

nếu người dùng nhấn tab alt hoặc hộp thông báo khác được hiển thị phía trên hộp thư mong muốn . trong kịch bản đó tôi đoán nó sẽ đóng một cái không mong muốn. – Vivekh

0

Tạo quyền kiểm soát của riêng bạn cho điều này và thực hiện hành vi bạn muốn có ở đó. Như một tùy chọn có thể có một bộ đếm thời gian để đóng MessageBox này.

2

Heres ví dụ của tôi với SendKeys - được kiểm tra và làm việc:

cho phép nói rằng chúng tôi có backgroundworker và nút in form. Sau khi bấm nút - bắt đầu công nhân và hiển thị hộp tin nhắn. Trong công nhân DoWork tổ chức sự kiện ngủ cho 5s và sau đó gửi nhập - hộp messsage đóng lại.

private void button1_Click(object sender, EventArgs e) 
{ 
    backgroundWorker1.RunWorkerAsync(); 
    MessageBox.Show("Close this message!"); 
} 

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Thread.Sleep(5000); 
    SendKeys.SendWait("{Enter}");//or Esc 
} 
+1

Tôi chỉ muốn chỉ ra rằng đối với giải pháp, điều quan trọng là phải kiểm tra xem có mở hộp tin nhắn không: một phím enter được gửi đến bất kỳ phần nào khác của Giao diện Người dùng có thể có những hậu quả không mong muốn ... – MartinStettner

+0

Có quan điểm của bạn là tốt. Cách giải quyết nhanh chóng của nó để nhập khóa rõ ràng là chìa khóa không tốt, tốt hơn để sử dụng esc - trong giao diện người dùng nó nên đại diện cho hủy bỏ. – Reniuz

+1

Giải pháp này chỉ hoạt động nếu người dùng không thay đổi tiêu điểm sang ứng dụng khác. Bạn không thể chắc chắn ứng dụng vẫn có tiêu điểm. Và Windows ngăn ứng dụng lấy tập trung từ một ứng dụng khác theo chương trình. – Alex

6

này link trên các diễn đàn MSDN cho thấy làm thế nào để đóng một hộp thông báo bằng cách sử dụng FindWindow và gửi thông điệp WM_CLOSE. Mặc dù câu hỏi đã được yêu cầu cho .NET/WindowsCE, nhưng nó có thể giải quyết vấn đề của bạn, nó có giá trị

+2

Tôi nghĩ rằng nó được coi là thực hành tốt để thêm ít nhất một chút thông tin bổ sung về cách trang được liên kết có thể giải quyết vấn đề (thay vì chỉ đăng liên kết trống). Tôi hy vọng bạn không nhớ rằng tôi đã thêm một mô tả ngắn. 1 anyway, đây có thể là một tài nguyên hữu ích. – MartinStettner

+0

Vâng martin, bạn hoàn toàn đúng. do thời gian phức tạp, tôi không thể thêm thông tin này. tuy nhiên cảm ơn bạn đã chỉnh sửa. :) – Bravo

7

Đây là một đoạn mã dựa trên UIAutomation (một API tuyệt vời nhưng vẫn chưa được sử dụng) cố gắng đóng tất cả các phương thức cửa sổ (trong đó có một mở với MessageBox) của quá trình hiện tại:

/// <summary> 
    /// Attempt to close modal windows if there are any. 
    /// </summary> 
    public static void CloseModalWindows() 
    { 
     // get the main window 
     AutomationElement root = AutomationElement.FromHandle(Process.GetCurrentProcess().MainWindowHandle); 
     if (root == null) 
      return; 

     // it should implement the Window pattern 
     object pattern; 
     if (!root.TryGetCurrentPattern(WindowPattern.Pattern, out pattern)) 
      return; 

     WindowPattern window = (WindowPattern)pattern; 
     if (window.Current.WindowInteractionState != WindowInteractionState.ReadyForUserInteraction) 
     { 
      // get sub windows 
      foreach (AutomationElement element in root.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window))) 
      { 
       // hmmm... is it really a window? 
       if (element.TryGetCurrentPattern(WindowPattern.Pattern, out pattern)) 
       { 
        // if it's ready, try to close it 
        WindowPattern childWindow = (WindowPattern)pattern; 
        if (childWindow.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction) 
        { 
         childWindow.Close(); 
        } 
       } 
      } 
     } 
    } 

Ví dụ, nếu bạn có một ứng dụng WinForms bật lên một MessageBox khi bạn nhấn một số button1, bạn sẽ vẫn có thể đóng ứng dụng sử dụng menu "Đóng cửa sổ" của Windows (nhấp chuột phải vào thanh tác vụ):

private void button1_Click(object sender, EventArgs e) 
    { 
     MessageBox.Show("Don't click me. I want to be closed automatically!"); 
    } 

    protected override void WndProc(ref System.Windows.Forms.Message m) 
    { 
     const int WM_SYSCOMMAND = 0x0112; 
     const int SC_CLOSE = 0xF060; 

     if (m.Msg == WM_SYSCOMMAND) // this is sent even if a modal MessageBox is shown 
     { 
      if ((int)m.WParam == SC_CLOSE) 
      { 
       CloseModalWindows(); 
       Close(); 
      } 
     } 
     base.WndProc(ref m); 
    } 

Bạn có thể sử dụng CloseModalWindows ở một nơi khác trong mã của bạn tất nhiên, đây chỉ là một mẫu.

+0

Không phải là UIAutomation cho WPF? Câu hỏi đặt ra là cho WinForms –

+0

@ErikFunkenbusch - Không biết ý bạn là gì đối với "đối với WPF". UIAutomation hỗ trợ bất kỳ loại ứng dụng. –

+0

Không gian tên System.Windows.Automation cho biết nó dành cho WPF. http://msdn.microsoft.com/en-us/library/ms747327(v=vs.110).aspx "Microsoft UI Automation là khung công tác trợ năng mới cho Microsoft Windows, có sẵn trên tất cả các hệ điều hành hỗ trợ Windows Presentation Foundation (WPF). " –

1

Tôi đã sử dụng .net 2 và hai phương pháp tiếp cận với cùng một mẹo.

Mở MessageBox từ cuống-Form với MessageBox.Show(this,"message")

Khi hình thức là không thể nhìn thấy hoặc không có thực sự UI.

  1. Giữ xử lý hình thức và đóng nó với:

    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 
    

    hoặc

  2. giữ hình thức như tham số lớp và sử dụng FormX.Close().

Vì biểu mẫu là chủ sở hữu của MessageBox, đóng nó sẽ đóng hộp thư.

1

Tham khảo DmitryG post in "Close a MessageBox after several seconds"

Auto-Đóng MessageBox sau thời gian chờ đạt

using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms; 

    public class AutoClosingMessageBox 
    { 
     System.Threading.Timer _timeoutTimer; 
     string _caption; 
     AutoClosingMessageBox(string text, string caption, int timeout) 
     { 
      _caption = caption; 
      _timeoutTimer = new System.Threading.Timer(OnTimerElapsed, 
       null, timeout, System.Threading.Timeout.Infinite); 
      MessageBox.Show(text, caption); 
     } 
     public static void Show(string text, string caption, int timeout) 
     { 
      new AutoClosingMessageBox(text, caption, timeout); 
     } 
     void OnTimerElapsed(object state) 
     { 
      IntPtr mbWnd = FindWindow(null, _caption); 
      if (mbWnd != IntPtr.Zero) 
       SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); 
      _timeoutTimer.Dispose(); 
     } 
     const int WM_CLOSE = 0x0010; 
     [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] 
     static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 
     [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] 
     static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 
    } 

và Gọi nó qua

AutoClosingMessageBox.Show("Content", "Title", TimeOut);