2010-05-15 35 views
32

Tôi đã thấy một số ứng dụng (có thể không phải ứng dụng .NET) có nút bổ sung ở bên trái từ nút thu nhỏ trên thanh tiêu đề của biểu mẫu? Làm thế nào tôi có thể đạt được điều này trong C#?Cách thêm nút phụ vào thanh tiêu đề của cửa sổ?

+2

Lưu ý rằng bạn không nên làm điều này: http://msdn.microsoft.com/en-us/library/aa974173(v=MSDN.10).aspx - »Không thêm điều khiển vào khung cửa sổ. Đặt các điều khiển bên trong cửa sổ thay vì « – Joey

+3

@Johannes, tôi thừa nhận đôi khi các ứng dụng thực hiện việc này có thể gây phiền nhiễu nhưng một số ứng dụng thực hiện điều đó rất tốt. Giống như Ultramon đặt một nút để trao đổi màn hình trên khung trông rất có nguồn gốc trong Windows 7. Vì vậy, có những ứng dụng làm điều đó một cách trang nhã. – Josh

+3

@Josh: Office 2007 cũng đã làm điều đó (nhưng đó không phải là lần xuất hiện đầu tiên của nhóm Office bỏ qua bất kỳ Nguyên tắc UX Windows nào). Tuy nhiên, tài liệu đó được viết bởi các chuyên gia UX và các nhà phát triển đơn thuần (hoặc khỉ mã) đang nỗ lực để bỏ qua chúng. Và vì lợi ích của người dùng, tôi nghĩ họ chỉ nên theo dõi, trừ khi họ có thể mang những người có kinh nghiệm và kiến ​​thức và - quan trọng nhất - kiểm tra khả năng sử dụng, để chứng minh khác đi. – Joey

Trả lời

32

CẬP NHẬT: Thêm một giải pháp mà sẽ làm việc với Aero kích hoạt cho Windows Vista và Windows 7


Non-Aero Solution

Khu phi-client của một sự tương tác cửa sổ được quản lý bởi một loạt các thông điệp specfic không phải của khách hàng. Ví dụ, thông điệp WM_NCPAINT được gửi đến thủ tục cửa sổ để vẽ vùng không phải của máy khách.

Tôi chưa bao giờ làm điều này từ .NET, nhưng tôi nghi ngờ bạn có thể vượt qua WndProc và xử lý các tin nhắn WM_NC * để đạt được những gì bạn muốn.

Cập nhật: Vì tôi chưa bao giờ thử tính năng này từ .NET. Tôi đã dành một vài phút và nghĩ rằng tôi sẽ thử nhanh chóng.

Thử tính năng này trên Windows 7, tôi thấy rằng tôi cần vô hiệu hóa Chủ đề cho cửa sổ nếu tôi muốn OS thực hiện hiển thị cơ sở của khu vực không phải khách hàng. Vì vậy, đây là một thử nghiệm ngắn. Tôi đã sử dụng GetWindowDC để lấy DC của toàn bộ cửa sổ hơn là GetDCEx, đó là vì tôi có thể interop từ bộ nhớ và không có tra cứu tất cả các hằng số cờ cho GetDcEx. Và tất nhiên mã có thể làm với nhiều kiểm tra lỗi hơn.

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

namespace WindowsFormsApplication1 
{ 
    public partial class CustomBorderForm : Form 
    { 
    const int WM_NCPAINT = 0x85; 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern IntPtr GetWindowDC(IntPtr hwnd); 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc); 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern void DisableProcessWindowsGhosting(); 

    [DllImport("UxTheme.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    public static extern IntPtr SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList); 

    public CustomBorderForm() 
    { 
     // This could be called from main. 
     DisableProcessWindowsGhosting(); 

     InitializeComponent(); 
    } 

    protected override void OnHandleCreated(EventArgs e) 
    { 
     SetWindowTheme(this.Handle, "", ""); 
     base.OnHandleCreated(e); 
    } 

    protected override void WndProc(ref Message m) 
    { 
     base.WndProc(ref m); 

     switch (m.Msg) 
     { 
     case WM_NCPAINT: 
      { 
      IntPtr hdc = GetWindowDC(m.HWnd); 
      using (Graphics g = Graphics.FromHdc(hdc)) 
      { 
       g.FillEllipse(Brushes.Red, new Rectangle((Width-20)/2, 8, 20, 20)); 
      } 
      int r = ReleaseDC(m.HWnd, hdc); 
      } 
      break; 
     } 
    } 
    } 
} 

Btw. Tôi gọi là DisableProcessWindowsGhosting, điều này sẽ ngăn hệ điều hành vẽ khu vực không phải khách hàng nếu ứng dụng mất quá nhiều thời gian để trả lời các thông báo của cửa sổ. Nếu bạn không làm điều này, sau đó trong một số trường hợp biên giới sẽ được renderd nhưng trang sức của bạn sẽ không được hiển thị. Vì vậy, điều đó phụ thuộc vào yêu cầu của bạn nó phù hợp với bạn hay không.


giải pháp

Xuất phát từ những nhận xét từ @TheCodeKing Aero hỗ trợ, tôi nghĩ tôi sẽ xem xét thêm về này. Nó chỉ ra điều này có thể được thực hiện một cách đầy đủ tài liệu trong khi hỗ trợ Aero. Nhưng nó không dành cho người yếu tim. Tôi sẽ không cung cấp một giải pháp hoàn chỉnh ở đây, vẫn còn một số kinks để tập luyện, nhưng nó cơ bản.

Mã này/giải pháp được dựa trên ví dụ Win32 có thể tìm thấy tại vị trí sau http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx

Về nguyên tắc những gì bạn cần làm là như sau.

  • Mở rộng khu vực khách hàng của cửa sổ để che khung. Điều này được thực hiện bằng cách xử lý thông báo WM_NCCALCSIZE và trả về 0. Điều này cho phép vùng Non-Client có kích thước bằng 0 và do đó khu vực khách hàng hiện bao gồm toàn bộ cửa sổ.
  • Kéo khung vào khu vực khách hàng bằng cách sử dụng DwmExtendFrameIntoClientArea. Điều này được hệ điều hành để render Frame trên khu vực khách hàng.

Các bước trên sẽ cung cấp cho bạn một cửa sổ có khung kính tiêu chuẩn, không bao gồm menu hệ thống (Biểu tượng cửa sổ) và tiêu đề.Các nút thu nhỏ, phóng to và đóng sẽ vẫn được vẽ và sẽ hoạt động. Những gì bạn sẽ không thể làm là kéo hoặc thay đổi kích thước cửa sổ, điều này là do khung không thực sự ở đó, hãy nhớ khu vực khách hàng bao phủ toàn bộ cửa sổ, chúng tôi đã yêu cầu hệ điều hành vẽ khung lên vùng máy khách.

Bây giờ bạn có thể vẽ trên cửa sổ như bình thường, ngay cả trên đầu khung. Bạn thậm chí có thể đặt điều khiển trong khu vực phụ đề.

Bước cuối cùng là xử lý thông điệp WM_NCHITTEST, đây là nơi bạn sẽ kiểm tra vị trí của con trỏ chuột và trả về chỉ báo cho biết các cửa sổ mà cửa sổ con chuột đã kết thúc. Ví dụ nếu bạn trả về HT_CAPTION, thì cửa sổ sẽ hoạt động như thể con chuột ở phía trên chú thích, và sẽ cho phép bạn kéo cửa sổ vv. Đây là chức năng sẽ yêu cầu triển khai hoàn chỉnh để có một cửa sổ đầy đủ chức năng với khung tùy chỉnh .

+0

Kỹ thuật này không hoạt động với kính aero. Tôi muốn được quan tâm nếu có ai biết voodoo cần thiết để có được trong làm việc trên kính. Cho đến nay tôi đã không tìm thấy bất kỳ ví dụ làm việc nào. – TheCodeKing

+0

@TheCodeKing, tôi đã cập nhật câu trả lời để trả lời câu hỏi của bạn. Tôi cũng đã prototyped này trong. NET chỉ để xác nhận rằng nó có thể được thực hiện để làm việc. Đây là bài viết MSDN mà tôi tham chiếu http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx –

+0

Thực ra điều đó nhắc tôi rằng tôi biết cách làm điều này, tôi có một số mã ở đâu đó , nó chỉ không hiển thị trong chế độ thiết kế như thế nào nó nhìn vào thời gian chạy.Bạn có một ví dụ C# của kỹ thuật bạn đã mô tả, tôi đã cố gắng nhất và họ không làm việc? – TheCodeKing

4

Tôi nghĩ một cách để làm điều này là xử lý tin nhắn WM_NCPAINT (sơn không phải khách) để vẽ nút và xử lý các nhấp chuột không phải của khách hàng để biết ai đó đã nhấp vào nút "".

3

Simple Giải pháp:

Bước 1: Tạo một Windows Form (điều này sẽ được thanh tiêu đề tùy chỉnh của bạn)

-Set Form Border Style to None 
-Add whatever controls you would like to this 
-I will name this custom form "TitleBarButtons" 

Bước 2. Trong từ mà bạn muốn sử dụng điều khiển tùy chỉnh này trong add

titleBarBtn = new TitleBarButtons(); 
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5); 
titleBarBtn.Show(); 
titleBarBtn.Owner = this; 

để constructor của bạn ... bạn có thể lộn xộn với các độ lệch này chỉ phù hợp ở một vị trí tốt đẹp cho ứng dụng của tôi

Bước 3. Thêm sự kiện chuyển sang hình thức chính của bạn

private void Form14_Move(object sender, EventArgs e) 
{ 
    titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5); 
} 

Xin vui lòng cho tôi biết nếu bạn muốn có một lời giải thích tốt hơn của bất kỳ của các mã trên.

+0

TitleBarButtons là gì? Cant dường như tìm thấy bất kỳ tài liệu tham khảo của lớp này. – Borik

+0

Tôi xin lỗi tôi nhận ra tôi không rõ ràng tôi tin rằng "TitleBarButtons" là biểu mẫu tùy chỉnh được thực hiện trong bước một. Ill sửa đổi câu trả lời của tôi để làm cho nó rõ ràng hơn. – hrh

+0

@hrh thread khá cũ mặc dù là nó có thể trong wpf quá, thêm hình thức để cửa sổ wpf – murmansk

Các vấn đề liên quan