Học WPF 4 trong 1 tuần – Ngày thứ 4: DataBinding and UI Architecture

images

Trong bài viết thứ 4 trong loạt bài này. Chúng ta sẽ tìm hiểu về WPF DataBinding, cách hiển thị, sắp xếp và lọc dữ liệu, cách thức sử dụng Model – View – ViewModel pattern, làm thế nào để xác thực người dùng nhập vào, tự tạo bộ chuyển đổi giá trị (ValueConverter) riêng, tăng cường mô hình MVVM bằng cách sử dụng các cách xử lý và hành động. Hy vọng với bài viết này tôi cũng như các bạn nhanh chóng hiểu được vấn đề. Thumbs up

1. DataBinding trong WPF (DataBinding in WPF)

image

1.1 Giới thiệu (Introduction)

– WPF cung cấp một cách đơn giản và mạnh mẽ để tự động cập nhật(auto-update) giữa các mô hình kinh doanh và giao diện người dùng (UI – User Interface). Cơ chế này được gọi là DataBinding. Mỗi khi dữ liệu trong mô hình kinh doanh (business model) của bạn thay đổi, nó sẽ tự động ánh xạ các cập nhật giao diện người dùng và ngược lại. Đây là một phương pháp được ưa thích trong WPF để đưa dữ liệu vào giao diện người dùng.

– DataBinding có thể một chiều (source –> target hoặc source <- target) hoặc 2 chiều (source <-> target ).

– Source của Databinding có thể là một thuộc tính bình thường trong .NET hay DependencyProperty. Các thuộc tính target(mục tiêu) của binding(gắn nối) phải là một DenpendencyProperty.

– Để làm việc với Databinding, cả 2 mặt của ràng buộc phải cung cấp một thông báo thay đổi có thể gọi đến các gắn kết(binding) khi giá trị mục tiêu (target value) được cập nhật. Các thuộc tính bình thường trong .NET này được thực hiện bằng cách tăng sự kiện PropertyChanged của INotifyPropertyChanged. DependentcyProperties được thực hiện bởi các cuộc gọi lại (callback) PropertyChanged của thuộc tính siêu dữ liệu (property metadata).

– DataBinding thường được thực hiện trong XAML bằng cách sử dụng  đánh dấu mở rộng  {Binding}. Ví dụ sau đây sẽ cho chúng ta thấy một liên kết đơn giản giữa các văn bản đơn giản của một Textbox và một Label ánh xạ kiểu giá trị.

<StackPanel>
      <TextBox x:Name="txtInput" />
      <Label Content="{Binding Text, ElementName=txtInput,   
                      UpdateSourceTrigger=PropertyChanged}" />
 </StackPanel>

1.2 DataContext

– Mỗi control trong WPF bắt nguồn từ FrameWorkElement có một thuộc tính DataContext. Thuộc tính này có nghĩa là để thiết lập để chúng ta có thể hình dung được đối tượng dữ liệu (data object). Nếu bạn không xác định rõ ràng source của databinding, data context sẽ được thiết lập mặc định (default).

– Các thuộc tính DataContext kế thừa giá trị của nó cho các phần tử con. Vì vậy bạn có thể đặt datacontext trên một layout container và  giá trị của nó được kế thừa từ tất cả các phần tử con. Điều này rất hữu ích nếu bạn muốn xây dựng một hình thức liên kết nhiều thuộc tính của các đối tượng dữ liệu giống nhau.

<StackPanel DataContext="{StaticResource myCustomer}">
      <TextBox Text="{Binding FirstName}"/>
      <TextBox Text="{Binding LastName}"/>
      <TextBox Text="{Binding Street}"/>
  <TextBox Text="{Binding City}"/>
</StackPanel>

1.3 Bộ chuyển đổi các giá trị (ValueConverter)

– Nếu bạn muốn gắn kết (bind) 2 thuộc tính khác loại với nhau, bạn cần phải sử dụng một ValueConverter. Một ValueConverter chuyển đổi một giá trị  từ kiểu nguồn(source type) sang kiểu đích (target type) và ngược lại. WPF đã có sẵn một số bộ chuyển đổi (converters) giá trị, nhưng trong hầu hết trường hợp, bạn sẽ cần phải tự viết riêng cho mình bằng cách bổ sung giao diện (interface) IValueConverter.

– Một ví dụ điển hình là gắn kết một số bool (boolean number) thành thuộc tính Visibility. Visibility này có thể là Visible (nhìn thấy), Collapsed (sụp đổ) hoặc Hidden (ẩn), bạn cần một công cụ chuyển đổi giá trị (converter).

<StackPanel>
   <StackPanel.Resources>
   <BooleanToVisibilityConverter x:Key="boolToVis" />
   </StackPanel.Resources>
 <CheckBox x:Name="chkShowDetails" Content="Show Details" />
   <StackPanel x:Name="detailsPanel"                 
     Visibility="{Binding IsChecked, ElementName=chkShowDetails,  
       Converter={StaticResource boolToVis}}">    
  </StackPanel>
</StackPanel>

Ví dụ dưới đây sẽ cho thấy một bộ chuyển đổi đơn giản (simple converter) là chuyển đổi kiểu bool sang một thuộc tính hiển thị (visibility property). Lưu ý, đây là một converter có sẵn trong .NET Framerwork.

public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,  CultureInfo culture)
{
   if (value is Boolean)
   {
      return ((bool)value) ? Visibility.Visible : Visibility.Collapsed;
   }
       return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
         throw new NotImplementedException();
}
}

* Mẹo nhỏ (tip): bạn có thể lấy được các giá trị chuyển đổi của bạn từ MarkupExtension và trả lại ví dụ riêng của mình bằng cách ghi đè (override) ProvideValue. Vì vậy bạn có thể sử dụng nó trực tiếp mà không cần phải tham chiếu nó từ một nguồn tài  nguyên (resource) nào.

2. Làm Thế nào để hiển thị, sắp xếp và lọc dữ liệu trong WPF (How to Navigate, Group, Sort and Filter Data in WPF).

2.1 CollectionView là gì? (What is a CollectionView?)

– WPF có một hạ tầng gắn kết dữ liệu (data binding) mạnh mẽ (powerful). Nó cho phép bạn gắn kết trực tiếp đến hầu hết bộ sưu tập(collection) để xem. Nhưng khi nói đến việc sắp xếp(sorting), lọc (filtering) và nhóm (grouping) hỗ trợ các bộ sư tập (collection) là rất hiếm. Đó là điểm mà các CollectionView thực hiện. Một collection view là một bao bọc (wrapper) xung quanh bộ sưu tập cung cấp các tính năng bổ sung sau đây:

    • Navigation (danh mục chính) .
    • Sorting (sắp xếp).
    • Filtering (lọc).
    • Grouping (nhóm).

2.2 Làm sao để tạo và sử dụng một CollectionView (How to create and use CollectionView)

Ví dụ dưới đây sẽ cho chúng ta thấy các tạo một CollectionView và gắn kết(bind) nó vào một Listbox.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
          <ListBox ItemsSource={Binding Customers} />
</Window>
public class CustomerView
{
         public CustomerView()
    {
        DataContext = new CustomerViewModel();
    }
}

public class CustomerViewModel
{
    private ICollectionView _customerView;

    public ICollectionView Customers
    {
        get { return _customerView; }
    }

    public CustomerViewModel()
    {
            IList<Customer> customers = GetCustomers();
            _customerView = CollectionViewSource.GetDefaultView(customers);
    }
}

2.3 Navigation (danh mục chính)

Collection view có hỗ trợ thêm các theo dõi các lựa chọn. Nếu bạn thiết lập thuộc tính IsSynchronizeWithCurrentItem là true thì bộ sưu tập có nghĩa vụ tự động đồng bộ hóa (synchronizes) các danh mục hiện hành của CollectionView và View.

<ListBox ItemsSource="{Binding Customers}" IsSynchronizedWithCurrentItem="True" />

– Nếu bạn sửu dụng mẫu MVVM (Model-View-ViewModel), bạn sẽ không cần phải thêm các SelectionItem của control bởi vì nó ngầm định hiển thị trên CollectionView.

IList<Customer> customers = GetCustomers();
ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.CurrentChanged = CustomerSelectionChanged;

private CustomerSelectionChanged(object sender, EventArgs e)
{
  // React to the changed selection
}

Bạn cũng có thể kiểm soát được sự lựa chọn từ các ViewModel bằng cách gọi phương thức MoveCurrentToFirst()  hoặc  MoveCurrentToLast() trên CollectionView.

2.4 Filter (Lọc)

– Để lọc một collection view bạn có thể định nghĩa một phương thức gọi lại, xác định xem danh mục(item) đó có có phải là một thành phần của view hay không. Đó là phương thức theo sau: bool Filter(object item). Bây giờ thiết lập các delegate cho phương thức cho thuộc tính Filter của collectionview.

ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.Filter = CustomerFilter;

private bool CustomerFilter(object item)
{
    Customer customer = item as Customer;
    return customer.Name.Contains( _filterString );
}

– Làm tươi bộ lọc (Refresh the Filter): Nếu bạn muốn thay đổi các tiêu chuẩn của bộ lọc và bạn muốn làm tươi (refresh) hiển thị (view). Bạn phải gọi trong Collection view (bộ sưu tập hiển thị).

public string FilterString
{
  get { return _filterString; }

  set {  _filterString = value;
         NotifyPropertyChanged("FilterString");
         _customerView.Refresh();
      }
}

2.5 Sắp xếp (sorting)

– Sắp xếp dữ liệu tăng dần (ascending) hay giảm dần (descending) bởi một hay nhiều tiêu chí là một nhu cầu phổ biến để xem dữ liệu. Collection view làm cho nó rất dễ đạt được mục tiêu này. Bạn chỉ cần add những SortDescriptions như bạn mong muốn vào các Collection view.

ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.SortDescriptions.Add( new SortDescription("LastName", ListSortDirection.Ascending );
_customerView.SortDescriptions.Add(new SortDescription("FirstName", ListSortDirection.Ascending );

– Sắp xếp nhanh (Fast Sorting):

Kỹ thuật sắp xếp ở trên là một kỹ thuật đơn giản và có thể xử lý chậm với một lượng dữ liệu lớn, bởi vì nó phản ánh việc sử dụng nội bộ. Nhưng có một cách thực hiện sắp xếp (sorting) khác tốt hơn bằng cách cung cấp một bộ sắp xếp tùy chỉnh (custom sorter).

ListCollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
      as ListCollectionView;_customerView.CustomSort = new CustomerSorter(); 
public class CustomerSorter : IComparer
{
    public int Compare(object x, object y)
    {
        Customer custX = x as Customer;
        Customer custY = y as Customer;
        return custX.Name.CompareTo(custY.Name);
    }
}

2.6. Nhóm (Grouping)

– Nhóm là một tính năng mạnh mẽ của Collection view. Bạn có thể định nghĩa nhiều nhóm như bạn thích bằng cách thêm GroupDescriptions trong collection view.

* Lưu ý: Grouping vô hiệu tính năng ảo hóa. Nó có thể mang lại vấn đề hiệu năng rất lớn về dữ liệu lớn. Vì vậy hãy cẩn thận khi sử dụng nó.

ICollectionView _customerView = CollectionViewSource.GetDefaultView(customers);
_customerView.GroupDescriptions.Add(new PropertyGroupDescription("Country"));

– Để tạo các nhóm hiển thị trong view bạn phải định nghĩa một GroupStyle đặc biệt trong view.

<ListBox ItemsSource="{Binding Customers}">
  <ListBox.GroupStyle>
       <GroupStyle.HeaderTemplate>
            <DataTemplate>
             <TextBlock Text="{Binding Path=Name}"/>
            </DataTemplate>
          </GroupStyle.HeaderTemplate>
    </ListBox.GroupStyle>
</ListBox>

2.7 Làm thế nào để tạo một collection view trong XAML (How to create a CollectionView in XAML).

Chúng ta hoàn toàn có thể tạo ra một collection view từ XAML.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 <Window.Resources>
        <CollectionViewSource Source="{Binding}" x:Key="customerView">
           <CollectionViewSource.GroupDescriptions>
               <PropertyGroupDescription PropertyName="Country" />
           </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Window.Resources>
    <ListBox ItemSource="{Binding Source={StaticResource customerView}}" />
</Window>

3. Sử dụng mẫu Model-View-ViewModel

3.1  Mẫu MVVM thân thiện  như thế nào?

–  WPF có tính năng Databinding rất mạnh mẽ, nó cung cấp 1 hay hai cách đơn giản để đồng bộ hóa các thuộc tính(properties). Bạn có thể gắn kết trực tiếp 2 phần tử WPF lại với nhau, nhưng theo thông thường databinding gắn kết một số loại dữ liệu để xem. Điều này được thực hiện bởi thuộc tính DataContext. Datacontext property được đánh dẫu là thuộc tính kế thừa. Nó có thể được thiết lập trên các phần tử gốc của view và giá trị của nó là kế thừa qua tất cả các yếu tố bên dưới của view.

–  Một hạn chế lớn của việc sử dụng DataContext property như một data source là nó chỉ là một đối tượng đơn. Nhưng trong một project trong thực tế bạn thường có nhiều hơn một đối tượng dữ liệu (data object) cho mỗi lần xem. Vậy chúng ta có thể làm gì? Phương pháp được sử dụng ở đây là các đối tượng dữ liệu bên trong một đối tượng đơn cho thấy nhiều dữ liệu được tổng hợp như các thuộc tính và nó có thể được ràng buộc với DataContext. Đối tượng này được gọi là view model.

3.2 Sự tách biệt giữa logic và trình diễn (Separation of logic and presentation)

–  Mô hình MVVM là một cách thân thiện để gắn kết các dữ liệu với view. Nhưng những hành động của người dùng, làm thế nào để điều khiển được chúng? Phương pháp cổ điển mà chúng ta đã biết khi lập trình windowForm là đăng ký một event handler và được thực hiện trong code phía dưới (code-behind) chương trình. Điều này có một số nhược điểm:images

– Có trường hợp xử lý trong code-behind xấu cho kiểm tra. Do đó bạn không thể mô phỏng các bước hiển thị.

–  Việc thay đổi thiết kế của view cũng thường đòi hỏi phải sửa code, bởi vì mỗi phần tử có các event handler khác nhau.

– logic là một ràng buộc chặc chẽ để hiển thị, không thể tái sử dụng các logic trong một hiển thị khác.

Vì vậy, ý tưởng được đưa ra là di chuyển toàn bộ logic trình bày đến view model bằng cách sử dụng một tính năng khác của WPF bằng các lệnh (command). Các lệnh có thể bị ràng buộc và được sự hỗ trợ trong nhiều phần tử như các button, togglebutton, menuitem, checkbox, và databinding. Mục tiêu ở đây là không có bất kỳ dòng logic trong code-behind của một view. Điều này có thể mang đến cho bạn những ưu điểm sau:

– View-model có thể dễ dàng kiểm tra và sử dụng bằng cách sử dụng các tiêu chuẩn unit-tests(thay vì UI testing).

– View có thể được thiết kế lại mà không cần phải thay đổi viewmodel. Bởi vì giao diện giống nhau.

– View-model thậm chí có thể được tái sử dụng trong một số trường hợp đặc biệt (điều này thường không được khuyến khích).

3.3  Sự khác nhau giữa MVVVM, MVP và MVC là gì? (What’s the difference between MVVVM, MVP and MVC?)

Chúng ta thường có sự nhầm lẫn giữa 3 mô hình kể trên, do đó chúng ta sẽ tìm hiểu sự khác nhau giữa 3 mô hình trên.

Mô hình MVC – Model View Controller

MVC là viết tắt chữ cái đầu của Models, Views, Controllers. MVC chia giao diện UI (User Interface) thành 3 phần tương ứng, đầu vào của các controller là các điều khiển thông qua HTTP request, model chứa các miền logic, view là những thứ được sinh ra trả về cho trình duyệt. Mô hình này được sử dụng tốt trong ASP.net MVC.

image

Mô hình MVP – Model View Presenterimage

Trong mô hình MVP, view nhận các đầu vào của người dùng và chuyển tiếp nó đến presenter. Presenter sửa đổi view hoặc model tùy thuộc vào hành động của người dùng. View và Presenter được kết hợp chặt chẽ, và chúng có quan hệ 2 chiều với nhau. Model không biết gì về presenter. View sẽ tự nó thụ lý, đó là lý do tại sao nó được gọi là mô hình presenter, kể từ lúc presenter đưa dữ liệu vào view. Mô hình này thường thấy trong WinForms và các ứng dụng WPF lúc trước.

Mô hình MVVM – Model-View-ViewModel.

imageMVVM là một mô hình điển hình của WPF. Nó bao gồm: view dùng để nhận tất cả các đầu vào của người dùng và chuyển tiếp nó vào ViewModel, thông thường bằng cách sử dụng lệnh,View thực hiện kéo dữ liệu từ các presenter bằng cách sử dụng databinding. Model không biết gì về view model.

3.4 Một số MVVM framework

Kiểm tra công cụ này để so sánh với MVVM framework. So sánh MVVM với tool(Silverlight).

4. Dữ liệu hợp lệ trong WPF (Data Validation in WPF)

Làm thế nào để chúng ta có thể kiểm tra và thông báo cho người dùng biết rằng dữ liệu mà họ nhập vào chưa hợp lệ trong WPF. Ví dụ như kiểm tra email nhập vào chưa đúng theo mẫu, nếu nhập không đúng email thì sẽ có một thông báo cho người dùng biết. Các phần trong mục này sẽ hướng dẫn các bạn từng bước để đạt được điều nói trên.

image

–  Đầu tiên bạn tạo một project WPF application. Sau đó sử dụng code dưới đây trong file MainWindow.xaml.

Lưu ý phải add thêm:

using System.Text.RegularExpressions;

<Grid  Height="350" Width="525" Background="Bisque">
   <TextBlock Height="20" HorizontalAlignment="Left" x:Name ="errormessage" VerticalAlignment="Top" Width="247" Margin="67,0,0,0" OpacityMask="Crimson" Foreground="#FFE5572C" />
   <TextBlock Height="23" HorizontalAlignment="Left" Margin="67,80,0,0" Name="textBlockEmailId" Text="EmailId" VerticalAlignment="Top" Width="110" />
   <TextBox Height="23" HorizontalAlignment="Left" Margin="183,80,0,0" Name="textBoxEmail" VerticalAlignment="Top" Width="222" />
   <Button Content="Submit" Height="23" HorizontalAlignment="Left" Margin="183,204,0,0" Name="Submit" VerticalAlignment="Top" Width="70" Click="Submit_Click" />
</Grid>

kết quả giống hình bên dưới.

image

–  Sau đó, bạn double click vào nút submit và viết lệnh cho sự kiện này trong file MainWindow.xaml.cs. Cụ thể code như sau:

if (textBoxEmail.Text.Length == 0 || passwordBox1.Password.Length == 0)
{
        errormessage.Text = "Enter an email.";
        textBoxEmail.Focus();
}
else if (!Regex.IsMatch(textBoxEmail.Text, @"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-          Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$"))
{
        errormessage.Text = "Enter a valid email.";
        textBoxEmail.Select(0, textBoxEmail.Text.Length);
        textBoxEmail.Focus();
}

Giống như hình dưới:

image

– Nhấn F5 để chạy chương trình. Ta được kết quả như hình bên dưới.

image

Khi nhập email không hợp lệ vào textbox nó sẽ có thông báo lỗi ngay trên form.

Bây giờ có thể đọc lại đoạn code để xem chúng xử lý như thế nào. Quan trọng nhất là chỗ else if  trong hàm xử lý sự kiện click của button submit.

Nếu bạn làm theo hướng dẫn mà vẫn không được thì có thể click vào đầy để download project demo của mình về

5. Tự tạo một bộ chuyển đổi giá trị (Create your own ValueConverter)

image

5. 1 Giới thiệu (introduction)

– Nếu bạn muốn gắn kết dữ liệu (databind) 2 thuộc tính có kiểu không tương thích, bạn cần một đoạn code ở giữa mới có thể chuyển đổi từ giá trị nguồn tới giá trị đích và ngược lại. Đoạn mã này gọi là ValueConverter. Một giá trị chuyển đổi là 1 class, được thực hiện trên giao diện đơn giản IValueConverter với 2 phương thức đối tượng Converter(object value) và đối tượng ConverterBack(object value).

5.2 Làm thế nào để thực hiện một ValueConverter (How to implement a ValueConverter)

– WPF cung cấp một số giá trị chuyển đổi, nhưng bấy nhiêu đó là không đủ để thực hiện những chuyển đổi đa dạng trong các yêu cầu của chúng ta. Để làm được điều này, bạn add thêm một class vào project của mình và đặt tên là [SourceType]To[TargetType]Converter, đây là cách đặt tên phổ biến nhất cho converter. Lưu ý các lớp và các hàm phải có thuộc tính là public thì mới có thể gọi các converter mà chúng ta tạo ra trong lớp khác.

public class BoolToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {        // Do the conversion from bool to visibility    }

    public object ConvertBack(object value, Type targetType,object parameter, CultureInfo culture)
    {        // Do the conversion from visibility to bool    }
}

5.3 Sử dụng ValueConverter trong XAML như thế nào? (How to use a ValueConverter trong XAML?)

– Điều đầu tiên bạn cần làm là để namespace của converter giống với namespace của namespace XAML. Sau đó bạn có thể tạo ra một phiên bản của một value converter trong resource của view và cho nó một cái tên. Sau đó bạn có thể tham chiếu nó bằng cách sử dụng {StaticResource}.

<Window x:Class="VirtualControlDemo.Window1"
    ...
    xmlns:l="clr-namespace:VirtualControlDemo"    ...>
    <Window.Resources>
        <l:BoolToVisibilityConverter x:Key="converter" />
    </Window.Resources>
    <Grid>
        <Button Visibility="{Binding HasFunction,             Converter={StaticResource converter}}" />
    </Grid>
</Window>

5.4 Đơn giản hóa việc sử dụng các valueconverter (Simplify the usage of valueconverter)

– Nếu bạn muốn sử dụng một valueconverter bình thường trong XAML, bạn phải thêm một thực thể (instance) của nó trong resource và tham chiếu nó bằng cách sử dụng một khóa (key). Điều này có thể hơi rờm rà, bởi vì key thường chỉ là tên của converter.

– Một thủ thuật đơn giản là chuyển đổi value converter từ MarkupExtension. Bằng cách này, chúng ta có thể tạo ra nó và sử dụng nó trong các ràng buộc như thế này Text={Binding Time, Converter={x:MyConverter}}. và nó khá là cool.

public abstract class BaseConverter : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
                   return this;
    }
}

5.5  StringFormat Converter.

StringFormat Converter là một converter hữu ích để điều khiển và định dạng của một   chuỗi chuyển đổi ngầm định của một đối tượng (ví dụ: gắn (bind) một DateTime vào một TextBlock) .

[ValueConversion(typeof(object), typeof(string))]
public class StringFormatConverter : BaseConverter, IValueConverter
{
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                    string format = parameter as string;
                    if (!string.IsNullOrEmpty(format))
                    {
                            return string.Format(culture, format, value);
                    }
                    else
                    {
                            return value.ToString();
                    }

 public object ConvertBack(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture)
 {
        return null;
 }
}

6. Hành vi (Behavior)

image

Hình bên là một Border đơn giản có thể được kéo thả bởi chuột – bằng một hành vi(behavior) kéo kèm theo.

6.1 Giới thiệu (introduction):

–  Hành vi (Behaviors) là một khái niệm mới, được giới thiệu trong Express Blend phiên bản 3, để đóng gói các chức năng thành phần vào và một tập hợp tái sử dụng (reusable component). Các tập hợp này có thể được đính kèm theo các control để cung cấp cho chúng một hành vi bổ sung.

– Những ý tưởng đằng sau các hành vi nhằm cung cấp cho các nhà thiết kế một tương tác linh hoạt hơn để thiết kế tương tác người dùng phức tạp mà không cần viết mã.

–  Ví dụ về hành vi kéo thả (drag & drop), kiểm tra đầu vào (input validation), xoay và phóng to (pan and zoom), thay đổi vị trí các phần tử (re-position of elements) … Danh sách các hành vi khả dụng rất dài.

– Hình ảnh một ứng dụng có một danh sách các khách hàng và người dùng và có thể thêm một số họ vào danh sách các thuê bao. Tương tác này có thể được thiết kế bằng cách cung cấp một nút “Add” bên cạnh mỗi thuê bao, nhưng nếu các nhà thiết muốn bổ sung thêm chức năng kéo thả, thì anh ta cần thảo luận với nhà phát triển và chờ cho đến khi công việc được hoàn tất. Giờ đây, chỉ cần kéo và thả vào các hành vi đã có trong danh sách mà Microsoft hỗ trợ sẵn.

6.2 Làm thế nào để xử dụng các hành vi trong Express Blend 3 (How to you behavior in Expression blend 3)

– Sử dụng các hành vi trong expression blend 3 chỉ đơn giản là add thêm một yếu tố và bề mặt thiết kế. Trong thư viện thuộc tính, bạn tìm thấy một mục mới gọi là “Behavior”. Nó liên kết với tất cả các hành vi có sẵn trong project của bạn. Chỉ cần lấy một trong các hành vi đó và kéo nó vào các phần tử mà bạn muốn thêm hành vi cho nó.

– Hành vi này xuất hiện như là một yếu tố con bên trong visual tree. Bằng cách nhấp vào nó, bạn có thể cấu hình (configure) các thuộc tính (properties) của hành vi.

image

image

6.3  Nó làm việc như thế nào (How does it work)

– Để thêm các hành vi cho một phần tử, bạn cần một số điểm mở rộng. Đây là một thuộc tính kèm theo gọi là Interaction.Behavior.

– Thuộc tính kèm theo giữ danh sách các hành vi cho phần tử đó thông qua một tham chiếu đến phần tử vào hành vi. Các hành vi trên có thể đăng ký chính nó vào các sự kiện, những thay đổi thuộc tính và những mở rộng chức năng của phần tử.

– Ý tưởng này đơn giản nhưng rất thông minh. Họ không cần một cơ sở hạ tầng mới, họ chỉ cần sử dụng lại một cái đã có.

<Border Background="LightBlue" >
    <e:Interaction.Behaviors>
        <b:DragBehavior/>
    </e:Interaction.Behaviors>
    <TextBlock Text="Drag me around!" />
</Border>

6.4  Làm thế nào để thực hiện các hành vi của chính bạn (How to implement your own behavior)

Ví dụ sau đây cho thấy việc thực hiện hành vi kéo mà chúng ta sử dụng ở trên. Chỉ cần xuất phát từ Behavior<T; gt  và ghi đè lên phương thức Attached.

public class DragBehavior : Behavior<UIElement>
{
    private Point elementStartPosition;
    private Point mouseStartPosition;
    private TranslateTransform transform = new TranslateTransform();

    protected override void OnAttached()
    {
        Window parent = Application.Current.MainWindow;
        AssociatedObject.RenderTransform = transform;

        AssociatedObject.MouseLeftButtonDown += (sender, e) =>
        {
            elementStartPosition = AssociatedObject.TranslatePoint( new Point(), parent );
            mouseStartPosition = e.GetPosition(parent);
            AssociatedObject.CaptureMouse();
        };
        AssociatedObject.MouseLeftButtonUp += (sender, e) =>
        {
            AssociatedObject.ReleaseMouseCapture();
        };

        AssociatedObject.MouseMove += (sender, e) =>
        {
            Vector diff = e.GetPosition( parent ) - mouseStartPosition;
            if (AssociatedObject.IsMouseCaptured)
            {
                transform.X = diff.X;
                transform.Y = diff.Y;
            }
        };
    }
}

6.5  Danh sách các hành vi phổ biến (List of some popular behavior)

Có rất nhiều các hành vi (behavior) để chúng ta dễ dàng thực hiện các tương tác người dùng. Và sau đây là những hành vi phổ biên nhất.

Hoàn thành ngày thứ 4

Xem thêm:

Học WPF 4 trong một tuần – Ngày 1: Bắt đầu (Getting Started).

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

Học WPF 4 trong một tuần – Ngày thứ 3: Layout and Controls

Advertisements

About thanhcuong1990

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

7 Responses to Học WPF 4 trong 1 tuần – Ngày thứ 4: DataBinding and UI Architecture

  1. ĐINH DUY TÀI says:

    Chào bạn!Cảm ơn vì bài viết bổ ích của bạn!Mình đang làm 1 đồ án về WPF.Mình sử dụng listview để hiền thị dữ liệu.Tuy nhiên khi mình insert dữ liệu vào listview thì listview không tự động hiển thị item mình vừa thêm vào,mình đã sử dụng listview.Items.Refresh() nhưng khộng được.Mong bạn giúp mình giải quyết vấn đề này!Cảm ơn bạn nhiều!

    • Chào bạn!
      Qua những thông tin mà bạn cung cấp thì mình không thể xác nhận bạn bị lỗi gì được. Nếu có thể bạn tham khảo bài viết về cách sử dụng control listview của mình thử: https://thanhcuong.wordpress.com/2011/04/09/s%E1%BB%AD-d%E1%BB%A5ng-control-listview-trong-c-using-listview-control-in-c/

      • ĐINH DUY TÀI says:

        Vấn đề của mình là như thế này.Mình đang làm 1 chương trình quản lý KTX bằng WPF.Trong đó sử mình dùng 1 listview để hiển thị thông tin các SV,Mình có 3 button Insert,Delete,Update để thao tác dữ liệu được hiển thị trên listview,Mình dùng ADO.NET để kết nối dữ liệu từ SQL server lên listview.Nói chung vấn đề ở đây là mình đã hiển thị dữ liệu lên listview chính xác,các thao tác thêm,xóa,sửa cũng chính xác.Tuy nhiên,Khi mình thực hiện 1 câu truy vấn insert,delete hoặc update dữ liệu vào databse,dữ liệu đó được chèn vào,tuy nhiên mình không biết dùng phương thức nào để listview tự động cập nhật lại cơ sở dữ liệu,hiển thị dòng thông tin mình vừa chèn vào.Nếu trong WinForm,giả sử khi mình insert dữ liệu,mình dùng cậu lệnh sau để cập nhật lại listview hoặc gridview:ListView.Items.Refresh().Tuy nhiên trong WPF,câu lệnh đó k có tác dụng.Mình có tham khảo trên mạng,họ dùng câu lệnh này:
        ICollectionView view = CollectionViewSource.GetDefaultView(ItemsSource);
        view.Refresh();
        hoặc sử dụng trigger

        Tuy nhiên mình làm chưa được.Mình mới tìm hiểu WPF nên không rành lắm về trigger .Mong bạn xem cách giải quyết nó thử giúp mình.Cảm ơn bạn nhiều!

      • Bạn xem cách giải quyết trên sự kiện propertychange của trang này xem sao nhé: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/f9cd4fb6-bddf-40cc-9dbe-41d20beda8b2/
        Nếu không được thì bạn thử đặt những khối lệnh bạn thay đổi trong listview.BeginUpdate() …. và listview.EndUpdate().

  2. hau says:

    Chào bạn! Cho mình hỏi mình cũng dùng WPF (và SQL server )làm một chương trình học toán tiểu học. Mình đã truy vấn được các cột dữ liệu cần thiết rồi vào DataTable rồi, mình cũng load vào ComboxBox được rồi, bạn có cách nào để Binding các dữ liệu vào các TextBox để khi mình chọn trong ComboBox thì các textbox cũng hiện ra tương ứng (kiểu như C# vậy đó nhưng trong này mình không bít đường)

  3. Trường says:

    cho mình hỏi làm sao cho một image di chuyển theo con trỏ……..có nghĩa là mình rê chuột ở đâu thì ảnh theo đó

  4. business model là mô hình nghiệp vụ chứ nhỉ ?

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