Tài liệu lập trình - WPF Tutorial - Sử dụng Custom Cursor
lượt xem 47
download
Các bạn có thể xem bài viết về sử dụng Custom Cursor trong WinForm ở đây. Bài hướng dẫn này cũng có nhiều vấn đề tương tự, cho nên mình nghĩ là bạn nên xem qua nó trước. Thật sự là tạo và sử dụng một con trỏ trong WPF khó khăn hơn rất nhiều so với trong WinForm. Điều này là do một vấn đề duy nhất - đó là WPF không dùng GDI, nhưng con trỏ thì lại dùng.
Bình luận(0) Đăng nhập để gửi bình luận!
Nội dung Text: Tài liệu lập trình - WPF Tutorial - Sử dụng Custom Cursor
- Tham gia ngày: Jun 2010 Bài gửi: 23 Cấp độ: 6 Nixforest Điểm: 299 Collaborators WPF Tutorial - Sử dụng Custom Cursor WPF Tutorial - Sử dụng Custom Cursor Các bạn có thể xem bài viết về sử dụng Custom Cursor trong WinForm ở đây. Bài hướng dẫn này cũng có nhiều vấn đề tương tự, cho nên mình nghĩ là bạn nên xem qua nó trước. Thật sự là tạo và sử dụng một con trỏ trong WPF khó khăn hơn rất nhiều so với trong WinForm. Điều này là do một vấn đề duy nhất - đó là WPF không dùng GDI, nhưng con trỏ thì lại dùng. Con trỏ là một thành phần quan trọng trong Window (nó cần cho tất cả các ứng dụng, hỗ trợ người dùng thao tác với Hệ điều hành), những lợi ích mà nó mang lại là điều không thể chối cãi, nhưng nó vẫn là đối tượng GDI. Cho nên ta cần phải vượt qua ranh giới này để có thể làm gì đó đặc biệt với con trỏ trong WPF. WPF vẫn hỗ trợ những cursor chuẩn, nhưng khi bạn muốn tạo một hình vẽ gì đấy cho cursor, phải làm nhiều việc đấy. Đầu tiên, bạn nhớ rằng, nếu muốn tạo một con trỏ trong WinForm, bạn phải dùng một số code như sau: PHP Code: IntPtr curPtr; /* CurPtr gets set to a pointer to an icon */ Cursor myCur = new Cursor(curPtr); Nhưng trong WPF, nó rất khác. Trong WinForm, đối tượng Cursor là System.Windows.Forms.Cursor, còn trong WPF, nó là System.Windows.Input.Cursor, và Constructor của class này ko hỗ trợ đối số nào là IntPtr cả. Nhưng cũng có một cách tương tự như trên: PHP Code: IntPtr ptr; /* CurPtr gets set to a pointer to an icon */ SafeFileHandle handle = new SafeFileHandle(ptr, true); Cursor myCur = System.Windows.Interop.CursorInteropHelper.Create(handle); Chúng ta sẽ convert một đối tượng IntPtr sang một đối tượng SafeHandle (SafeFileHandle kế thừa từ SafeHandle - bạn không thể tạo một đối tượng SafeHandle, vì nó là một abstract class). Sau đó bạn khởi tạo Cursor từ phương thức System.Windows.Interop.CursorInteropHelper.Create với đối số là đối tượng SafeHandle đó. Chúng ta liên kết code các phần trên, sẽ có một lớp như sau: PHP Code:
- using System; using System.Windows.Interop; using Microsoft.Win32.SafeHandles; using System.Runtime.InteropServices; using System.Windows.Input; namespace WPFCursorTest { public class CursorHelper { private struct IconInfo { public bool fIcon; public int xHotspot; public int yHotspot; public IntPtr hbmMask; public IntPtr hbmColor; } [DllImport("user32.dll")] private static extern IntPtr CreateIconIndirect(ref IconInfo icon); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); public static Cursor CreateCursor(System.Drawing.Bitmap bmp, int xHotSpot, int yHotSpot) { IconInfo tmp = new IconInfo(); GetIconInfo(bmp.GetHicon(), ref tmp); tmp.xHotspot = xHotSpot; tmp.yHotspot = yHotSpot; tmp.fIcon = false; IntPtr ptr = CreateIconIndirect(ref tmp); SafeFileHandle handle = new SafeFileHandle(ptr, true); return CursorInteropHelper.Create(handle); } } } Bạn cần lưu ý rằng chúng ta đang sử dụng một đối tượng System.Drawing.Bitmap ở đây (bạn nên Add Reference thư viện System.Drawing để có thể sử dụng nó). Đây là một đối tượng Bitmap dạng GDI cũ - một khái niệm nằm ngoài các lớp WPF. Mặc định WPF không sử dụng thư viện System.Drawing cho nên bạn cần phải Add chúng vào (Project/ Add Reference...). Mình đã thử, khá khó, để tìm ra một cách tạo một con trỏ trong WPF mà không cần phải dựa vào System.Drawing.Bitmap. Mình cần phải nhận được một con trỏ (Pointer chứ không phải Cursor) Icon trỏ ra ngoài bitmap (như hàm GetHicon), nhưng đối tượng bitmap trong WPF lại không thể tạo ra một Pointer nào cả.
- Nhưng ko phải đã hết hi vọng! Hãy thử với một overload của phương thức CreateCursor dưới đây xem: PHP Code: public static Cursor CreateCursor(UIElement element, int xHotSpot, int yHotSpot) { element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); element.Arrange(new Rect(0, 0, element.DesiredSize.Width, element.DesiredSize.Height)); RenderTargetBitmap rtb = new RenderTargetBitmap((int)element.DesiredSize.Width, (int)element.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32); rtb.Render(element); PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(rtb)); MemoryStream ms = new MemoryStream(); encoder.Save(ms); System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms); ms.Close(); ms.Dispose(); Cursor cur = InternalCreateCursor(bmp, xHotSpot, yHotSpot); bmp.Dispose(); return cur; } Ở đây, mình dùng một UIElement - cốt lõi của cấu trúc WPF. Mình đo đạc và sắp xếp nó để chắc chắn nó được trả về những giá trị đúng, và sau đó mình "tạo một bức ảnh từ nó". Mình thực hiện bằng cách tạo một đối tượng RenderTargetBitmap. Đây là một lớp đối tượng trong WPF cho phép bạn lấy một đối tượng UIElement và vẽ nó lên một bitmap - nhưng nhớ là, đây là bitmap của WPF (chính xác là một đối tượng System.Windows.Media.Imaging.RenderTargetBitmap). Nó không giống như đối tượng System.Drawing.Bitmap. Mình hiệu chỉnh kích thước cho nó, sau đó render UIElement trên bitmap đó. Bây giờ mình có một đối tượng RenderTargetBitmap trong tay, mình muốn tạo một đối tượng System.Drawing.Bitmap. Microsoft hoàn toàn có khả năng làm điều này dễ dàng hơn (nhưng họ không làm), và mình thực sự khó chịu về nó. Có một vài phương pháp cho phép bạn chuyển từ đối tượng System.Drawing.Bitmap sang đối tượng bitmap của WPF, nhưng ngược lại thì hoàn toàn không. Ít nhất là mình chưa thể tìm ra. Nếu có bạn nào biết những phương thức tương tự như vậy (hoặc tốt hơn cách mình đã miêu tả), hãy chia sẻ^_^. Mình dùng một Encoder, và mã hóa bitmap (RenderTargetBitmap) như một đối tượng PNG (bạn có thể mã hóa như thế nào tùy thích). Sau đó, mình tạo một MemoryStream và lưu mã của bitmap (đã được mã hóa) vào trong stream đó. Tiếp theo mình tạo một đối tượng System.Drawing.Bitmap với Contructor có tham số là một MemoryStream. Nên nhớ phải giải phóng các đối tượng không dùng đến nữa. Toàn bộ code chúng ta cần ở đây: PHP Code: using System; using System.Windows.Interop; using Microsoft.Win32.SafeHandles; using System.Runtime.InteropServices; using System.Windows.Input; using System.Windows.Media;
- using System.Windows.Media.Imaging; using System.IO; using System.Windows; namespace WPFCursorTest { public class CursorHelper { private struct IconInfo { public bool fIcon; public int xHotspot; public int yHotspot; public IntPtr hbmMask; public IntPtr hbmColor; } [DllImport("user32.dll")] private static extern IntPtr CreateIconIndirect(ref IconInfo icon); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp, int xHotSpot, int yHotSpot) { IconInfo tmp = new IconInfo(); GetIconInfo(bmp.GetHicon(), ref tmp); tmp.xHotspot = xHotSpot; tmp.yHotspot = yHotSpot; tmp.fIcon = false; IntPtr ptr = CreateIconIndirect(ref tmp); SafeFileHandle handle = new SafeFileHandle(ptr, true); return CursorInteropHelper.Create(handle); } public static Cursor CreateCursor(UIElement element, int xHotSpot, int yHotSpot) { element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); element.Arrange(new Rect(0, 0, element.DesiredSize.Width, element.DesiredSize.Height)); RenderTargetBitmap rtb = new RenderTargetBitmap((int)element.DesiredSize.Width, (int)element.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32); rtb.Render(element); PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(rtb)); MemoryStream ms = new MemoryStream(); encoder.Save(ms);
- System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms); ms.Close(); ms.Dispose(); Cursor cur = InternalCreateCursor(bmp, xHotSpot, yHotSpot); bmp.Dispose(); return cur; } } } Bây giờ là cách sử dụng class: PHP Code: public partial class CursorTest : Window { public CursorTest() { InitializeComponent(); TextBlock tb = new TextBlock(); tb.Text = "{ } Switch On The Code"; tb.FontSize = 10; tb.Foreground = Brushes.Green; this.Cursor = CursorHelper.CreateCursor(tb, 5, 5); } } Và kết quả là: Translate from http://www.switchonthecode.com __________________ Try my best...
CÓ THỂ BẠN MUỐN DOWNLOAD
-
Tài liệu Windows Presentation Foundation: Bài 2 Các điều khiển (control) cơ bản của WPF
20 p | 102 | 21
-
Tài liệu Windows Presentation Foundation: Bài 3 Các điều khiển nâng cao trong ứng dụng WPF
20 p | 118 | 20
-
THỰC ĐƠN (MENU) VÀ THANH CÔNG CỤ (TOOLBAR) - WPF
16 p | 186 | 11
-
Tài liệu Windows Presentation Foundation: Bài 7 Kiểu hiển thị (Style) và Khuôn mẫu (Template)
20 p | 103 | 10
-
Kiểu hiển thị (Style) và Khuôn mẫu (Template)
13 p | 92 | 7
Chịu trách nhiệm nội dung:
Nguyễn Công Hà - Giám đốc Công ty TNHH TÀI LIỆU TRỰC TUYẾN VI NA
LIÊN HỆ
Địa chỉ: P402, 54A Nơ Trang Long, Phường 14, Q.Bình Thạnh, TP.HCM
Hotline: 093 303 0098
Email: support@tailieu.vn