2010-09-20 47 views
15

Tôi có tình trạng này. Application.OpenForms không trả về kết quả phù hợp. tức là Application.OpenForms.Count = 0 luôn luôn ..Application.OpenForms.Count = 0 luôn luôn

Mục đích nhận biểu mẫu là lấy chủ sở hữu của Biểu mẫu để tôi có thể chuyển chủ sở hữu làm tham số của hàm MessageBox.Show().

+0

Vui lòng cung cấp thêm thông tin. – SLaks

+0

Nếu tôi kiểm tra Application.OpenForms.Count ở dạng tải nó cho thấy tôi 1. Một cái gì đó là lạ với bạn ứng dụng, bạn cần phải cung cấp thêm chi tiết về làm thế nào để tái sản xuất vấn đề. –

+0

Ứng dụng của tôi có dạng chính. Mặc dù tôi có biểu mẫu được mở tại thời điểm mã này được thực thi, nó trả về 0. Cảm ơn Albin, SLaks – Ananth

Trả lời

34

Có lỗi trong Windows Forms làm cho biểu mẫu biến mất khỏi bộ sưu tập Application.OpenForms. Điều này sẽ xảy ra khi bạn chỉ định các hộp thoại ShowInTaskbar, FormBorderStyle, Hộp điều khiển, Min/MaximizedBox, RightToLeftLayout, HelpButton, Opacity, TransparencyKey, ShowIcon hoặc MdiParent sau khi cửa sổ được tạo. Các thuộc tính này đặc biệt ở chỗ chúng được chỉ định làm cờ kiểu trong lệnh gọi CreateWindowEx() gốc. Biểu mẫu mẫu này minh họa lỗi:

public partial class Form1 : Form { 
    public Form1() { 
     InitializeComponent(); 
     button1.Click += button1_Click; 
    } 
    private void button1_Click(object sender, EventArgs e) { 
     Console.WriteLine(Application.OpenForms.Count); 
     this.ShowInTaskbar = !this.ShowInTaskbar; 
     Console.WriteLine(Application.OpenForms.Count); 
    } 
} 

Biểu mẫu Windows phải gọi lại cho CreateWindowEx() để thay đổi thuộc tính hiệu quả, chuyển các cờ kiểu khác nhau. Phá hủy cửa sổ ban đầu đầu tiên có các hiệu ứng phụ vượt ra ngoài nhấp nháy rất đáng chú ý, một trong số đó là lớp Ứng dụng mất dấu vết của biểu mẫu vì nó thấy cửa sổ biến mất. Với lỗi mà nó không thêm nó trở lại khi cửa sổ mới được tạo ra. Tránh lỗi bằng cách thiết lập thuộc tính chỉ trong hàm tạo, mã chạy trước khi CreateWindowEx() được gọi, không phải trong bất kỳ trình xử lý sự kiện nào.

Nói chung, tránh dựa vào OpenForms do lỗi này. Cung cấp cho lớp cần hiển thị hộp thông báo một tham chiếu đến cá thể biểu mẫu thông qua hàm tạo của nó. MessageBox thường tự tìm ra một cửa sổ chính, btw, nó sẽ chọn cửa sổ đang hoạt động và đúng 99% thời gian. Nếu bạn cần nó để gọi BeginInvoke() từ một chuỗi công nhân thì hãy chắc chắn sao chép SynchronizationContext.Current trong constructor của bạn và gọi phương thức Post() của nó sau này. Đảm bảo thư viện của bạn cũng sẽ hoạt động với các thư viện lớp GUI khác.

+0

MessageBox sử dụng phương thức Win32 API GetActiveWindow có thể trả lại một cửa sổ không thuộc về ứng dụng của bạn. Tốt hơn là không nên dựa vào điều này và luôn tự xác định chính cửa sổ chủ sở hữu. – Tergiver

+1

@Tergiver: GetActiveWindow chỉ có thể trả về một cửa sổ xử lý cho một cửa sổ đã được tạo trên cùng một luồng. http://msdn.microsoft.com/en-us/library/ms646292%28VS.85%29.aspx –

+0

Bạn là chính xác. Tôi xin lỗi, tôi dường như nhận được phương pháp API của tôi bối rối. – Tergiver

0

Tôi gặp sự cố khi tôi sử dụng ShowInTaskBar = true. Tôi đã giải quyết nó bằng cách sử dụng API cửa sổ thay vì thuộc tính .Net. Application.OpenForms vẫn nguyên vẹn.

Tôi không biết nếu nó hoạt động như một cách giải quyết chung bằng cách sử dụng SetWindowLong để thay đổi thuộc tính nhưng nó hoạt động cho ShowInTaskBar = true.

public static class ShowInTaskBar { 

    [DllImport("User32.dll")] 
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); 
    [DllImport("User32.dll")] 
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex); 

    [DllImport("user32.dll")] 
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 

    private const int SW_HIDE = 0x00; 
    private const int SW_SHOW = 0x05; 

    private const int WS_EX_APPWINDOW = 0x40000; 
    private const int GWL_EXSTYLE = -0x14; 

    public static void ShowWindowInTaskbar(IntPtr pMainWindow) { 
     SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow, GWL_EXSTYLE) | WS_EX_APPWINDOW); 

     ShowWindow(pMainWindow, SW_HIDE); 
     ShowWindow(pMainWindow, SW_SHOW); 
    } 

    public static void HideWindowFromTaskbar(IntPtr pMainWindow) { 
     SetWindowLong(pMainWindow, GWL_EXSTYLE, GetWindowLong(pMainWindow, GWL_EXSTYLE) | ~WS_EX_APPWINDOW); 

     ShowWindow(pMainWindow, SW_HIDE); 
     ShowWindow(pMainWindow, SW_SHOW); 
    } 
} 
Các vấn đề liên quan