Học WPF 4 trong một tuần – Ngày 2: Các khái niệm về WPF

images

Sau ngày thứ nhất. Chúng ta đã biết một số khái niệm về các công cụ phát triển và khả năng của WPF, chúng ta cũng tạo được chương trình WPF đầu tiên. Trong ngày thứ 2 này. Chúng ta bắt đầu tìm hiểu về những khái niệm cụ thể hơn như XAML, các mối quan hệ thứ bậc trong WPF, tìm hiểu về sự kỳ diệu đằng sau DependencyProperties và làm quen với các sự kiện định tuyến…

1. Giới thiệu XAML (Introduction to XAML)

XAML là viết tắt của (eXtensible Application Markup Language), là một ngôn ngữ đơn giản dựa trên XML để xây dựng và khởi tạo các đối tượng .Net với các quan hệ cấp bậc. Ngày nay, XAML được sử dụng để tạo ra các giao diện người dùng trong WPF, Silverlight, kê khai quy trình công việc trong WF và giấy điện tử trong tiêu chuẩn XPS.

Tất cả các lơp trong WPF có các ít hàm khởi tạo tham số và tạo ra, sử dụng nhiều thuộc tính. Điều đó được thực hiện để phù hợp ngôn ngữ XML tựa XAML.

1.1 Ưu điểm của XAML (Advantages of XAML):

Bạn có thể làm tất cả các công việc trong XAML, kể cả code. XAML không chỉ cần một cách khác để xây dựng và khởi tạo đối tượng. Bạn có thể sử dụng XAML cho cả dự án WPF của mình. Nó phụ thuộc vào bạn, nếu bạn muốn khai báo nó trong XAML hay viết nó trong Code.

Khai báo giao diện người dùng trong XAML có một số lợi thế sau:

–  XAML có mã ngắn, rõ ràng dễ đọc.

–  Tách mã thiết kế và logic.

–  Công cụ thiết kế đồ họa như Expression Blend yêu cầu source XAML .

–  Việc tách XAML và giao diện người dùng logic cho phép tách tách biệt rõ ràng vai trò của nhà thiết kế và nhà phát triển.

1.2. XAML so với code (XAML vs. Code)

Ví dụ chúng ta xây dựng một StackPanel đơn giản với texblok và 1 button trong XAML và so sánh nó với mã được viết ra trong C#.

– Với XAML thì mã là:

<StackPanel >
                <TextBlock  Margin = "20" > Chào mừng đến với XAML </ TextBlock >
       <Button  Margin = "10"  HorizontalAlignment = "Right" > OK </ Button >
</ StackPanel >

– Với C#:

// Create the StackPanelStackPanel stackPanel = new StackPanel();this.Content = stackPanel;

// Create the TextBlockTextBlock textBlock = new TextBlock();textBlock.Margin = new Thickness(10);textBlock.Text = "Chào mừng bạn đến với XAML";stackPanel.Children.Add(textBlock);

// Create the ButtonButton button = new Button();button.Margin= new Thickness(20);button.Content = "OK";stackPanel.Children.Add(button);

Chúng ta dễ dàng nhận ra phiên bản XAML ngắn hơn nhiều và dễ đọc. Và đó là sức mạnh biểu cảm của XAML.

1.3. Các thuộc tính như là các yếu tố trong XML(Properties as Elements)

Các thuộc tính thông thường được viết giống như chúng ta đã biết trong XML <Button Content = “OK” />.  Nhưng nếu chúng ta muốn đặt thêm một đối tượng phức tạp hơn ví dụ như một hình ảnh có các thuộc tính và lưới điều khiển? Để làm được điều đó, chúng  ta sử dụng cú pháp phần tử thuộc tính (properties element). Điều này cho phép chúng ta trích xuất các thuộc tính như một phần tử nhỏ riêng. Ví dụ sau đây minh họa điều đó:

<Button>  <Button.Content>     <Image Source="Images/OK.png" Width="50" Height="50" />  </Button.Content></Button>

1.4 Chuyển đổi kiểu ngầm định (Implicit type conversion).

Một kiến trúc rất mạnh của WPF là chuyển đổi kiểu ngầm định. Chúng làm công việc của mình một cách âm thầm dưới background. Khi bạn khai báo một BorderBrush, từ “Blue” chỉ là một chuỗi (string). Các BrushConverter ngầm định sẽ được tạo ra từ System.Windows.Media. Brushes.Blue. Cũng liên quan Borther Thickness đó là các chuyển đổi ngầm định bên trong đối tượng Thickness. WPF có rất nhiều loại chuyển đổi để xây dựng các lớp, nhưng bạn cũng có thể viết các kiểu chuyển đổi riêng cho class của mình.

<Border BorderBrush="Blue" BorderThickness="0,10"></Border>

1.5 Đánh dấu mở rộng (Markup Extension)

Markup Extensions giữa một vị trí năng động cho các giá trị thuộc tính của XAML. Chúng giải quyết các giá trị của một thuộc tính trong thời gian chạy. Markup Extensions được khai báo trong dấu ngoặc nhọn (Ví dụ như:  Background = “{ StaticResource NormalBackgroundBrush }” ). WPF có một số được xây dựng trong Markup Extensions, nhưng bạn có thể viết riêng cho mình bằng cách phát sinh từ MarkupExtension. Dưới đây là các cách xây dựng Markup extension.

– Binding (gắn kết): để liên kết các giá trị của 2 thuộc tính với nhau.

– StaticResource:  Một thời gian nghiên cứu một mục của resource.

– DynamicResource: Tự động cập nhật tra cứu một mục của resource.

– TemplateBinding: Để liên kết một thuộc tính của một control template với các thuộc tính phục thuộc của control.

– x: Static : Giải quyết các giá trị của các thuộc tính tĩnh(static property).

– y:Null : trả về Null.

Các định danh đầu tiên trong một cặp dấu ngoặc là tên của phần tử mở rộng. Tất cả các định danh được đặt tên các tham số theo hình thức Property = Value. Ví dụ sau đây sẽ cho chúng ta thấy một nhãn có nội dung liên kết với văn bản trong textbox. Khi bạn gõ một văn bản vào textbox, các thuộc tính của văn bản thay đổi và liên kết mở rộng đánh dấu sẽ tự động cập nhật nội dung của nhãn(label).

<TextBox x:Name="textBox"/><Label Content="{Binding Text, ElementName=textBox}"/>

1.6 NameSpace (Không gian tên)

Vào đầu mỗi file XAML bạn cần 2 namespace:

Đầu tiên là: http://schemas.microsoft.com/winfx/2006/xaml/presentation. Đây là ánh xạ với tất cả các điều khiển WPF trong System.Windows.Controls.

Thứ 2 là:  http://schemas.microsoft.com/winfx/2006/xaml. Nó là ánh xạ với System.Windows.Markup dùng để định nghĩa các từ khóa trong XAML.

Việc ánh xạ giữa một XML namespace và một CLR namespace được thực hiện bởi các thuộc tính XmlnsDefinitions ở cấp độ lắp ráp (assembly). Bạn cũng có thể trực tiếp khai báo một CLR namespace trong XAML bằng cách sử dụng tiền tố(prefix) clr-namespace.

<Window
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml>
 </Window>

2. Các mối quan hệ cấp bậc của các phần tử trong WPF

Logical – và Visual Tree

image

2.1 Giới thiệu (Introduction)

Các phần tử (elements) của một giai diện người dùng trong WPF được phân thành các cấp liên quan. Mối liên quan này được gọi là Logical Tree. Các template của một phần tử bao gồm nhiều visual elements – cây này gọi là Visual Tree. WPF có sự khác nhau giữa 2 cây, bởi vì đối với một số vấn đề bạn chỉ cần các yếu tố logic (elements logical) và cho các vấn đề khác mà bạn muốn tất cả các yếu tố.

<Window>
       <Grid>
        <Label Content="Label" />
                   <Button Content="Button" />
       </Grid>
 </Window>

2.2 Tại sao chúng ta cần phải có 2 loại cây khác nhau

– Một WPF control bao gồm nhiều primitive controls. Một Button – ví dụ – bao gồm một khung hình chữ nhật và nội dung bên trong khung đó. Những control này là gọi là visual children (tạm gọi là những khía cạnh trực quan) của một button.

– Khi WPF hiển thị một button, yếu tố chính của nó sẽ không hiển thị, nhưng nó duyệt qua visual tree và biểu diễn các visual children của nó.

– Mối quan hệ phân cấp này cũng có thể được sử dụng để làm hit-testing, layout (bố trí)…

– Nhưng đôi khi bạn không quan tâm đến các đường viền hay các hình chữ nhật của một mẫu điều khiển. Một đặc thù là các template có thể thay thế và vì thế không nên liên hệ với visual tree. Do đó, bạn muốn có một cây mạnh mẽ hơn và chỉ chứa các điều khiển thực mà không phải tất cả các bộ phận của template. Và Logical Tree hôi tụ những điều kiện đó.

2.3 Logical Tree (Cây logic)

Các Logical Tree mô tả các mối quan hệ giữa các yếu tố của giao diện người dùng. Logical Tree có trách nhiệm:

– Kế thừa các giá trị DependencyProperty.

– Giải quyết các tham chiếu DynamicResource.

– Tìm kiếm tên các phần tử cho các gắn kết(binding).

– Forwaring RoutedEvent.

2.4 Visual Tree (Cây trực quan)

Visual Tree chứa tất cả các yếu tố logic bao gồm tất cả các yếu tố trực quan của template hay mỗi một phần tử (element). Visual Tree có trách nhiệm:

– Biểu diễn các yếu tố trực quan (rendering visual elements).

– Lan truyền phần tử opacity (propagate element opacity).

– Lan truyền layout and RenderTransforms.

– Lan truyền các thuộc tính IsEnalbed (propagate the IsEnalbed property).

– Kiểm tra lượt truy cập (do hit-testing).

– RelativeSource(FindAncestor).

2.5 Lập trình tìm một hình thức nguyên thủy (ancestor) trong visual tree

Nếu bạn là một phần tử con trong giao diện người dùng và bạn muốn truy cập dữ liệu từ một yếu tố cha mẹ (parent element). Nhưng bạn không biết rằng làm thế nào để tìm các phần tử của các cấp trên đó, và giải pháp tốt nhất là điều hướng trên cây cho đến khi nó tìm thấy phần tử đã được yêu cầu.

Đây là mã lệnh các bạn có thể tham khảo. Bạn cũng có thể sử dụng mã lệnh này tương tự trên logical tree.


public static class VisualTreeHelperExtensions
{
    public static T FindAncestor<T>(DependencyObject dependencyObject)
        where T : class
    {
        DependencyObject target = dependencyObject;
        do
        {
            target = VisualTreeHelper.GetParent(target);
        }
        while (target != null && !(target is T));
        return target as T;
    }
}

ví dụ sau đây cho thấy làm thế nào để sử dụng mã lệnh trên. Nó bắt đầu ở đây và điều hướng lên visual tree cho đến khi nó tìm thấy một yếu tố kiểu lưới (Grid). Nếu không tìm được nó trả về NULL.

var grid = VisualTreeHelperExtensions.FindAncestor<Grid>(this);

3. Tìm hiểu sự kỳ diệu đằng sau Dependency Properties

3.1 Giới thiệu (introduction)

– Khi bắt đầu phát triển các ứng dụng với WPF,  có thể bạn sẽ sớm vấp ngã trước DependencyProperties. Nó trông khá giống với các properties bình thường khác trong .Net, nhưng khái niệm bên dưới của nó là phức tạp và mạnh mẽ hơn nhiều.

– Sự khác biệt chính ở đây là, giá trị của một property bình thường trong .Net là đọc trực tiếp từ một private member trong class của bạn. Trong khi các giá trị của DependencyProperty được giải quyết tự động khi gọi GetValue() . Khóa của đầu vào là tên của thuộc tính và giá trị là giá trị mà bạn muốn đặt cho thuộc tính đó.

– Những ưu điểm của Dependency Property:

+ Giảm dung lượng bộ nhớ (reduced memory footprint):  chúng ta thường mất một lượng  lớn bộ nhớ để lưu trữ một trường cho từng thuộc tính khi bạn nghĩ rằng hơn 90% các thuộc tính điều giao diện người dùng (UI – User Interface) thông thường ở giá trị ban đầu của nó. Dependency Properties giải quyết vấn đề này chỉ bằng sửa đổi cách thức lưu trữ các thuộc tính được tạo ra. Các giá trị mặc định được lưu trữ một lần trong dependency property.

+ Kế thừa giá trị (Value Inheritance):  Khi bạn truy cập một dependency property, giá trị được giải quyết bằng cách sử dụng một giá trị chính xác. Nếu không có giá trị cục bộ (value local) được thiết lập, các dependency property điều hướng trên logical tree cho đến khi nó tìm thấy một giá trị. Khi bạn thiết lập các FontSize trên phần tử gôc, nó sẽ được áp dụng cho tất cả các textblock bên dưới nó, ngoại trừ trường hợp bạn ghi đè(override)  lên giá trị.

+ Thay đổi thông báo (change notification): các Dependency property được xây dựng một cơ chế thay đổi thông báo. Bằng cách đăng ký một cuộc gọi lại trong thuộc tính metadata bạn nhận được thông báo khi giá trị của thuộc tính bị thay đổi. Điều này cũng được sử dụng bởi các databinding.

3.2 Chiến lược giải quyết giá trị (Value resolution strangely)

Mỗi khi bạn truy cập một thuộc tính phụ thuộc (Dependency Property), nó giải quyết trong nội bộ giá trị bằng cách làm theo thứ tự ưu tiên từ cao xuống thấp. Nó kiểm tra nếu một giá trị cục bộ có sẵn, hoặc một tùy chỉnh style được kích hoạt,… và tiếp tục cho đến khi nó tìm thấy một giá trị. Cuối cùng, giá trị mặc định là luôn luôn khả dụng.

image

3.3 Sự kỳ diệu đằng sau Dependency Properties (The magic behind it)

– Mỗi control WPF đăng ký một bộ Dependency Properties trong class DependencyProperty. Mỗi một phần tử trong chúng là thành phần của một khóa(là duy nhất của mỗi loại) và một siêu dữ liệu (metadata) chứa các cuộc gọi lại và một giá trị mặc định.

– Tất cả các kiểu muốn sử dụng DependencyProperties phải xuất phát từ DependencyObject. Lớp cơ sở này định nghĩa một khóa, giá trị từ điển đó chứa các giá trị cục bộ của các thuộc tính phụ thuộc (dependency properties). Khóa của một đầu vào (entry) là một khóa đã được định nghĩa với dependency property.

– Khi bạn truy cập một thuộc tính phụ thuộc trong .NET, nó kế thừa các cuộc gọi GetValue(DependencyProperty) để truy cập giá trị. Phương pháp này giải quyết được các giá trị bằng cách sử dụng một chiến lượt giải quyết giá trị được giải thích chi tiết dưới đây. Nếu một giá trị cục bộ là khả dụng, nó đọc nó trực tiếp từ từ điển. Nếu không có giá trị được thiết lập, thì tìm kiếm trên logical tree một giá trị kế thừa. Nếu không, các giá trị được tìm thấy nó có giá trị mặc định quy định tại các thuộc tính siêu dữ liệu (property metadata). Trình tự này có vẻ hơi đơn giản, nhưng nó cho thấy một khái niệm chính.

image

3.4 Làm thế nào để tạo một DependencyProperty (How to create a DenpendencyProperty)

– Để tạo một DependencyProperty, add một trường tĩnh kiểu DependencyProperty và gọi DependencyProperty.Register() để tạo một dependencyProperty. Tên của DependencyProperty luôn phải kết thúc với …Property. Đây là một quy ước đặt tên trong WPF.

– Để cho nó có thể được truy cập một cách bình thường như các thuộc tính khác trong .NET bạn cần phải thêm một thuộc tính wrapper. Wrapper này không có gì khác so với các tiếp nhận bên trong và thiết lập các giá trị sử dụng GetValue(), SetValue(). Các phương thức được kế thừa từ DependencyObject và qua các DependencyProperty như khóa (key).

— Chú ý quan trọng:  Không thêm bất kỳ logic vào các thuộc tính này. Bởi vì chúng chỉ được gọi khi bạn thiết lập các thuộc tính từ code. Nếu bạn thiết lập thuộc tính từ XAML, phương thức SetValue() được gọi trực tiếp.

Nếu bạn sử dụng Visual Studio, bạn có thể gõ prodb và nhấn 2 lần tab để tạo ra một dependency property.


// Dependency Property
public static readonly DependencyProperty CurrentTimeProperty = 
     DependencyProperty.Register( "CurrentTime", typeof(DateTime),
     typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now));

// .NET Property wrapper
public DateTime CurrentTime
{
    get { return (DateTime)GetValue(CurrentTimeProperty); }
    set { SetValue(CurrentTimeProperty, value); }
}

Mỗi một DependencyProperty cung cấp các cuộc gọi lại để thông báo thay đổi giá trị cưỡng chế và xác nhận. Những cuộc gọi lại (callbacks) được đăng ký trong DependencyProperty.


 
new FrameworkPropertyMetadata( DateTime.Now, 
                       OnCurrentTimePropertyChanged, 
                       OnCoerceCurrentTimeProperty ),
                       OnValidateCurrentTimeProperty );

3.5 Gọi lại giá trị được thay đổi (Value changed callback)

Các cuộc gọi thông báo thay đổi là một phương thức tĩnh, nó được gọi mỗi khi giá trị TimeProperty thay đổi. Các giá trị mới thông qua trong EventArgs, các đối tượng mà giá trị được thay đổi là hợp quy cách với source.


private static void OnCurrentTimePropertyChanged(DependencyObject source, 
        DependencyPropertyChangedEventArgs e)
{
    MyClockControl control = source as MyClockControl;
    DateTime time = (DateTime)e.NewValue;
    // Put some update logic here...
}

3.6 Gọi lại cưỡng chế (Coerce Value Callback)

Các cuộc gọi lại cưỡng chế cho phép bạn điều chỉnh giá trị nếu nó không ném ra một ngoại  lệ (exception). Ví dụ như một thanh tiến trình với một giá trị đặt bên dưới giá trị nhỏ nhất hoặc trên giá trị lớn nhất. Trong trường hợp này chúng ta có thể cưỡng chế giá trị trong phạm vi cho phép. Trong ví dụ dưới đây, chúng ta sẽ giới hạn thời gian trong quá khứ:

private static object OnCoerceTimeProperty( DependencyObject sender, object data )
{
    if ((DateTime)data > DateTime.Now )
    {
        data = DateTime.Now;
    }
    return data;
}

3.7 Xác nhận gọi lại (Validation Callback)

Trong xác nhận gọi lại bạn kiểm tra nếu giá trị thiết lập là hợp lệ. Nếu bạn trả về false, AgrumentException sẽ được ném ra. Ví dụ:

private static bool OnValidateTimeProperty(object data)
{
    return data is DateTime;
}

3.8 DependencyProperties chỉ đọc (Read Only)

–    Một số DependencyProperty của WPF controls là chỉ đọc. Chúng thường được sử dụng để báo cáo các trạng thái của control, ví dụ như thuộc tính IsMouserOver.

– Có khi nào bạn tự hỏi rằng tại sao không sử dụng một thuộc tính bình thường của .NET. Một lý do quan trọng không thể thiết lập kích hoạt cho các thuộc tính bình thường của các thuộc tính .NET.

– Tạo một thuộc tính chỉ đọc tương tự như việc tạo ra một DependencyProperties bình thường. Thay vì gọi DependencyProperty.Register() bạn có thể gọi DependencyProperty.RegisterReadOnly(), nó sẽ trả về cho bạn một DependencyPropertyKey. Key này được lưu trữ trong private hay protected static chỉ đọc các trường trong Class của bạn. Key cho phép bạn truy cập và thiết lập giá trị từ bên trong class của bạn và sử dụng nó như một DependencyProperty thông thường.

– Điều thứ 2 cần làm là đăng ký một public Dependency Property được thực hiện bởi DependencyPropertyKey.DependencyProperty. Thuộc tính này là thuộc tính chỉ đọc và có thể truy cập từ bên ngoài.

// Register the private key to set the value
private static readonly DependencyPropertyKey IsMouseOverPropertyKey =
      DependencyProperty.RegisterReadOnly("IsMouseOver",
      typeof(bool), typeof(MyClass),
      new FrameworkPropertyMetadata(false));

// Register the public property to get the value
public static readonly DependencyProperty IsMouseoverProperty =
      IsMouseOverPropertyKey.DependencyProperty;    

// .NET Property wrapper
public int IsMouseOver
{
   get { return (bool)GetValue(IsMouseoverProperty); }
   private set { SetValue(IsMouseOverPropertyKey, value); }
}

3.9 Các thuộc tính cố định (Attached Properties)

Attached Properties là một dạng đặc biệt của DependencyProperties. Cho phép bạn đính kèm một giá trị vào một đối tượng mà không cần biết gì về giá trị này.

– Một ví dụ cho khái niệm này là bố trí các bảng (layout panels). Mỗi layout panel  cần các dữ liệu khác nhau để sắp xếp các phần tử con của nó. Ví dụ như: một Canvas cần Top và Left, DockPanel cần Dock… Từ đó bạn có thể viết layout panel của mình  trong một danh sách dài vô hạn. Bạn thấy đấy, nó không có khả năng có tất cả các thuộc tính đó trên tất cả các control của WPF. Và giải pháp được đưa ra là attached properties – chúng được định nghĩa bởi control cần một dữ liệu từ một control khác trong một bối cảnh cụ thể. Ví dụ như một yếu tố được liên kết bởi một parent layout panel.

–  Để thiết lập một giá trị  của một Attached Properties, ta thêm một thuộc tính trong XAML với tiền tố của phần tử cung cấp Attached Properties. Để thiết lập các thuộc tính  Cavas.Top và Cavas.Left của một button liên kết với một Cavas panel, bạn có thể viết như thế này:

<Canvas>
    <Button Canvas.Top="20" Canvas.Left="20" Content="Click me!"/>
</Canvas>
public static readonly DependencyProperty TopProperty =
    DependencyProperty.RegisterAttached("Top",
    typeof(double), typeof(Canvas),
    new FrameworkPropertyMetadata(0d,
        FrameworkPropertyMetadataOptions.Inherits));

public static void SetTop(UIElement element, double value)
{
    element.SetValue(TopProperty, value);
}

public static double GetTop(UIElement element)
{
    return (double)element.GetValue(TopProperty);
}

 

3.10 Nghe các thay đổi DependencyProperties (Listen dependency properties changes)

Nếu bạn muốn lắng nghe những thay đổi của một DependencyProperty, bạn có thể phân lớp theo kiểu được định nghĩa trong property và ghi đè lên các property metadata và thông qua một PropertyChangedCallback. Nhưng một cách dễ dàng hơn nhiều để được DependencyPropertyDescriptor và hookup một cuộc gọi lại bằng lời gọi AddValueChanged().

DependencyPropertyDescriptor textDescr = DependencyPropertyDescriptor.
    FromProperty(TextBox.TextProperty, typeof(TextBox));

if (textDescr!= null)
{
    textDescr.AddValueChanged(myTextBox, delegate
    {
        // Add your propery changed logic here...
    });
}

 

3.11 Làm thế nào để xóa một giá trị cục bộ

Bởi vì null là một giá trị cục bộ hợp lệ, ta sử dụng hằng DependencyProperty.UnsetValue để thực hiện hủy thiết lập giá trị.

button1.ClearValue( Button.ContentProperty );

 

4. Định tuyến sự kiện (Routed Event)

image

Routed Events là sự điều hướng các sự kiện lên hoặc xuống visual tree theo RoutingStrategy của chúng. Các chiến lượt định tuyến có thể là bubble, tunnel hay direct. Bạn có thể  xử lý các sự kiện được có sắn trên các yếu tố đó đặt ra hoặc có thể xử lý bên dưới nó bằng cách xử dụng các cú pháp sự kiện kèm theo: Button.Click = “Button_Click”.

Routed Event thông thường xuất hiện theo cặp. Đầu tiên là một sự kiện tunneling (truyền đa giao thức) được gọi PreviewMouseDown và thứ 2  bubbling(nổi bọt) được gọi MouseDown. Chúng sẽ không dừng lại cho đến khi một sự kiện được xử lý. Để ngăn chặn việc định tuyến bạn phải thiết lập một giá trị: e.Handle = true;

– Tunneling: sự kiện được đưa ra trên các yếu tố gốc và điều hướng xuống visual tree cho đến khi nó đạt được các resource element hoặc cho đến khi Tunneling dừng bằng cách đánh dấu sự kiện này đã được xử lý (handled). Tên quy ước nó được gọi là Preview… và xuất hiện trước sự kiện bubbling tương ứng.

– Bubbling (nổi bọt): sự kiện này được đưa ra nhờ các phần tử source và điều hướng lên visual tree cho đến khi nó đạt đến các phần tử gốc hoặc cho đến khi bubbling dừng lại bằng cách đánh dấu sự kiện này đã được xử lý (handled). Sự kiện bubbling xuất hiện sau Tunneling.

–  Direct (trực tiếp): sự kiện xuất hiện nhờ các phần tử source và phải được xử lý trên các source elements của chính nó. Hành vi này cũng giống như sự kiện bình thường trong .NET.

* Làm thế nào để tạo một Routed Event tùy biến (How to create a custom Routed Event)

// Register the routed event
public static readonly RoutedEvent SelectedEvent =
    EventManager.RegisterRoutedEvent( "Selected", RoutingStrategy.Bubble,
    typeof(RoutedEventHandler), typeof(MyCustomControl));

// .NET wrapper
public event RoutedEventHandler Selected
{
    add { AddHandler(SelectedEvent, value); }
    remove { RemoveHandler(SelectedEvent, value); }
}

// Raise the routed event "selected"
RaiseEvent(new RoutedEventArgs(MyCustomControl.SelectedEvent));

 

Bài viết này có một số thuật ngữ khó hiểu, trong quá trình tham khảo các tài liệu tiếng anh mình khó có thể dịch ra chính xác được. Mong các bạn thông cảm. Đến đây xem như xong ngày thứ 2.

Advertisements

About thanhcuong1990

Handsome and talent!! ^^
This entry was posted in WPF. Bookmark the permalink.

8 Responses to Học WPF 4 trong một tuần – Ngày 2: Các khái niệm về WPF

  1. ip camera says:

    Excellent post, l quite agree with your conclusion. However lam having problem subscribing to your rss.

  2. Hải says:

    Khó hiểu quá :((
    Nhiều chỗ đọc như google dịch vậy

  3. Nixforest says:

    Quá khó hiểu luôn!!! Hic

  4. Vũ Tiến Lâm says:

    quá hay ý chứ, một số chỗ đọc tài liệu thấy hiểu chưa rõ lắm, thao khảo thêm của bạn rất bổ ích ^^ Thanks

  5. Hoàng Hải says:

    hết ngày thứ 2 và chưa ngộ được ra mấy
    đọc như google dịch ý bác ạ, bác thêm ít ví dụ có phải dễ hiểu hơn ko @@

  6. Mình rất quan tâm đến các thuộc tính phụ thuộc, cơ mà đọc vẫn chưa hiểu lắm, bạn có thể diễn đạt theo ý hiểu cua bạn được không ?

  7. Quân says:

    Bạn có bài nào hướng dẫn làm một phần mềm với WPF như quản lý nhà trọ chẳng hạn, mình rất hứng thú nhưng không biết nên làm như thế nào? VD: Như nhấn buttun nó chạy ra cửa sổ khác trong cửa sổ cũ……Mong bạn giúp đỡ newbie như mình, Cảm ơn!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s