11/19/11

WPF: Ràng buộc một mảng các đối tượng vào một ListBox

Một cách Windows Presentation Foundation (WPF) mang dữ liệu đến người dùng được thông qua data binding. Bài này tạo ra một đối tượng ràng buộc ví dụ chương trình sử dụng một WPF ListBox. Ví dụ sử dụng một kiến trúc điển hình Model-View-Controller.
Mô tả:
Hãy tưởng tượng nhận task hiển thị mảng của các object. Một cách tiếp cận sẽ được lặp qua mảng và thực hiện "toString" trên mỗi đối tượng xuất ra các kết nối của tất cả các chuỗi. Điều này là ngớ ngẩn, làm như vậy là không hiệu quả. Chắc chắn, nếu những gì cần phải được hiển thị hay thay đổi bạn chỉ có thể cập nhật thực hiện đối tượng toString tương ứng và được thực hiện. Tuy nhiên, nếu đối tượng đã thay đổi như vậy mà đại diện cho nó bằng một chuỗi mô tả đơn giản là không đủ, sau đó sẽ có một vấn đề lớn. Rất nhiều phần sẽ phải thay đổi để thích ứng với việc hiển thị mảng bằng cách khác. Sử dụng kiến trúc MVC tạo ra một lớp business và hình ảnh hoạt động logic cụ thể cho một số các tính linh hoạt mong muốn.

Mã nguồn của bài viết này có sẵn ở đây .
Đối với thời gian và tính đơn giản, giả định rằng dữ liệu đã đến lúc điều khiển từ một số data source. Dữ liệu này sẽ được hiển thị cho người dùng trong một "cách làm hài lòng."(Ít nhất là những gì tôi xem cho một ví dụ nhanh chóng.)
The type of data to be displayed is contained in a small object (“ClassInfo”) as defined below. Các loại dữ liệu để hiển thị được chứa trong một object nhỏ ("ClassInfo") theo quy định dưới đây. Để bây giờ nó sẽ chỉ giữ tên của một class cụ thể. (Chúng ta sẽ cập nhật nó sau đó với một phần data bằng cách sử dụng một kiểu dữ liệu khác nhau.)
ClassInfo.cs:
View Code:
namespace ObjectDatabindingExample
{
public class ClassInfo
{
public string Name { get; set; }
}
}

Các định nghĩa class tiếp theo chúng ta cần phải thấy là controller. Như đã đề cập trước đó, người ta cho rằng controller đã nhận được các mảng của objects ClassInfo cần để hiển thị. Lớp điều khiển class sẽ bắt đầu vụn vặt và chỉ bao gồm các mảng của các object ClassInfo. Xem dưới đây.
ClassController.cs:
View Code:
namespace ObjectDatabindingExample
{
public class ClassController
{
#region Private Members

private readonly ClassInfo[] _data = new ClassInfo[] {
new ClassInfo() { Name = “Calculus II” },
new ClassInfo() { Name = “Physics” },
new ClassInfo() { Name = “AI Algorithms and Design Considerations” },
new ClassInfo() { Name = “Programming Patterns” },
new ClassInfo() { Name = “Computer Networks” },
new ClassInfo() { Name = “Building and Programming Robots” },
new ClassInfo() { Name = “Distributed Systems” }
};

#endregion
}
}

Suy nghĩ về việc này cho một thời điểm, có vẻ như chúng ta sẽ muốn hiển thị dữ liệu này bằng cách nào đó. Tiếp theo cho việc tạo ra lớp View. (Trong trường hợp này "ClassView.") Xem dưới đây cho các XAML, các mã sau chỉ đơn giản là mặc định cho hiện tại.
ClassView.xaml:
View Code:
<Window x:Class=”ObjectDatabindingExample.ClassView”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Object Data Binding Example” Height=”300″ Width=”300″>
<Grid>
</Grid>
</Window>




ClassView là "View", và ClassController là "điều khiển" trong kiến trúc MVC. Các lớp tiếp theo cần thiết là một "mô hình" (trong trường hợp này "ClassModel") sẽ được những gì người xem gắn vào và những gì controller cập nhật dữ liệu. Xem ClassModel là định nghĩa dưới đây.
ClassModel.cs:
View Code:
namespace ObjectDatabindingExample
{
public class ClassModel
{
}
}

Được rồi, điều này làm tăng các kiến trúc ban đầu của ví dụ nhỏ. Tuy nhiên, không có mối liên kết đã được thực hiện giữa các đối tượng / lớp. Chúng ta biết rằng controller cần cập nhật các mô hình với dữ liệu của nó, và ClassView sẽ bị ràng buộc với thuộc tính trên mô hình đó. Hãy cung cấp cho các mô hình một thuộc tính mà sẽ lưu trữ các đối tượng ClassInfo cho nó bằng controller. Chúng ta sẽ sử dụng một ObservableCollection trong lớp mô hình để có thể ràng buộc ClassView trực tiếp đến thuộc tính của ClassModel thay đổi định nghĩa như sau.
ClassModel.cs:
View Code:
using System.Collections.ObjectModel;

namespace ObjectDatabindingExample
{
public class ClassModel
{
public ObservableCollection<ClassInfo> Classes { get; set; }
}
}

Tiếp theo, chúng ta biết rằng ClassView sẽ phải bind vào và hiển thị các thuộc tính này. Kể từ khi tiêu đề của bài viết này sử dụng một ListBox, đó là những gì chúng ta sẽ sử dụng. ClassView định nghĩa thay đổi sau.
ClassView.xaml:
View Code:
<Window x:Class=”ObjectDatabindingExample.ClassView”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Object Data Binding Example” Height=”300″ Width=”300″>
<Grid>
<ListBox />
</Grid>
</Window>




Hình ảnh sau khi thêm <ListBox />
Được rồi, bây giờ chúng ta biết những gì có thể nhìn thấy đối tượng sẽ bị ràng buộc ClassModel, hãy di chuyển tiếp bằng cách cho ClassView tạo ra một ví dụ của ClassModel mà nó sẽ gắn vào. Hiện nay chúng ta không có quyền truy cập của dự án code của chúng ta từ bên trong ClassView XAML. Để khắc phục điều này chúng ta có thể thêm không gian tên dự án của chúng ta trong việc mở thẻ "<Window>" với một không gian tên định danh. Tôi đang tự ý lựa chọn sử dụng " local " như nhãn để đại diện cho tên miền không gian của dự án. Bây giờ chúng ta có quyền truy cập cho các đối tượng dự án, ClassView có thể tạo ra một ví dụ của ClassModel trong tài nguyên của từ điển. Xem dưới đây để thay đổi.
ClassView.xaml:
View Code:
<Window x:Class=”ObjectDatabindingExample.ClassView”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:local=”clr-namespace:ObjectDatabindingExample”
Title=”Object Data Binding Example” Height=”300″ Width=”300″ Loaded=”Window_Loaded”>

<Window.Resources>
<local:ClassModel x:Key=”model” />
</Window.Resources>

<Grid>
<ListBox />
</Grid>
</Window>

Ở đây, điều quan trọng cần lưu ý. Khi bạn tạo một đối tượng để sử dụng trong nguồn tài nguyên từ điển (như chúng ta đã thực hiện với đối tượng ClassModel của chúng ta) là cần thiết. Yêu cầu này có ý nghĩa vì chúng ta sau này sẽ muốn lấy đối tượng từ trong từ điển.
Di chuyển về phía trước, để cho ClassController có thể sửa đổi các đối tượng ClassModel chính xác, ClassView sẽ cho ví dụ ClassModel đến ClassController. Đối với mục đích của chúng ta, điều này sẽ được thực hiện trên các sự kiện cửa sổ tải. Đây là lần đầu tiên chúng ta phải thay đổi code behind trong ClassView. Chúng ta có thêm một xử lý sự kiện trong đoạn code sau để được gọi sau khi tải cửa sổ. Xem cả hai định nghĩa dưới đây.
ClassView.xaml:
View Code:
<Window x:Class=”ObjectDatabindingExample.ClassView”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:local=”clr-namespace:ObjectDatabindingExample”
Title=”Object Data Binding Example” Height=”300″ Width=”300″ Loaded=”Window_Loaded”>

<Window.Resources>
<local:ClassModel x:Key=”model” />
</Window.Resources>

<Grid>
<ListBox />
</Grid>
</Window>

ClassView.xaml.cs:
using System.Windows;

namespace ObjectDatabindingExample
{
public partial class ClassView : Window
{
public ClassView()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
}
}

Trong ClassView.xaml.cs Window_Loaded (object, RoutedEventArgs) được gọi cửa sổ sau khi đã được nạp, và hy vọng sau khi ClassModel đã được tạo ra và thêm vào từ điển của cửa sổ. Tiếp theo chúng ta phải thực hiện sự kiện này bằng cách lấy các ví dụ của ClassModel từ các nguồn lực từ điển và cho nó đến ClassController. ClassView phải có một cách để cung cấp cho các đối tượng ClassModel, ClassController, vì vậy chúng ta sẽ thực hiện một phương thức Initialize (ClassModel) trên controller mà lưu trữ một tham chiếu đến ClassModel. Phương thức này sẽ được gọi là khởi tạo từ Window_Loaded của ClassView xử lý sự kiện.
ClassView.xaml.cs:
View Code:
using System.Windows;

namespace ObjectDatabindingExample
{
public partial class ClassView : Window
{
public ClassView()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
ClassModel model = this.Resources["model"] as ClassModel;
this._controller.Initialize(model);
}
catch { /* Chomp, chomp! */ }
}

#region Private Members

private ClassController _controller = new ClassController();

#endregion
}
}

ClassController.cs:
View Code:
namespace ObjectDatabindingExample
{
public class ClassController
{
public void Initialize(ClassModel model)
{
this._model = model;
}

#region Private Members

private ClassModel _model;

private readonly ClassInfo[] _data = new ClassInfo[] {
new ClassInfo() { Name = “Calculus II” },
new ClassInfo() { Name = “Physics” },
new ClassInfo() { Name = “AI Algorithms and Design Considerations” },
new ClassInfo() { Name = “Programming Patterns” },
new ClassInfo() { Name = “Computer Networks” },
new ClassInfo() { Name = “Building and Programming Robots” },
new ClassInfo() { Name = “Distributed Systems” }
};

#endregion
}
}

Được rồi, ClassController hiện tại có một tham chiếu đến các đối tượng cùng ClassModelClassView sẽ ràng buộc. Hãy để chúng ta đi trước và liên kết các ListBox trong ClassView cho ObservableCollection bằng các ví dụ mô hình.
ClassView.xaml:
View Code:
<Window x:Class=”ObjectDatabindingExample.ClassView”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:local=”clr-namespace:ObjectDatabindingExample”
Title=”Object Data Binding Example” Height=”300″ Width=”300″ Loaded=”Window_Loaded”>

<Window.Resources>
<local:ClassModel x:Key=”model” />
</Window.Resources>

<Grid>
<ListBox ItemsSource=”{Binding Classes, Source={StaticResource model}}” />
</Grid>
</Window>

Vì đây là lý do tại sao chúng ta ở đây, chúng ta hãy phân tích các báo cáo này. Xác nhận:
<ListBox ItemsSource=”{Binding Classes, Source={StaticResource model}}” />

Chúng ta có một ListBox có nguồn gốc là kết quả của "{ Binding Classes , Source ={ StaticResource model }} Phần đầu tiên này (“ { Binding Classes , …”) quy định rằng chúng ta muốn sở hữu ItemsSource trên ListBox bị ràng buộc đối với thuộc tính class trong DataContext hiện hành. Để cho liên kết với việc tham khảo các thuộc tính class trên ClassModel chúng ta có trong nguồn tài nguyên từ điển ClassView, chúng ta ghi đè lên DataContext hiện tại bằng cách xác định các thuộc tính Nguồn trong báo cáo để trỏ đến các tài nguyên từ điển chính của ClassModel , cụ thể là "Model." “{ StaticResourcemodel } “ trả về một mục từ các nguồn tài nguyên tĩnh từ đó là liên kết với key "model." Toàn bộ khoản ràng buộc đối với thuộc tính class về các đối tượng trong từ điển có nguồn tài nguyên chính là "model."
Vì vậy, ClassView bây giờ ràng buộc đối với thuộc tính class về một thể hiện của ClassModel,ClassController có một tham chiếu đến trường hợp đó. Chúng ta hãy cố gắng điều khiển toàn bộ MVC này / ý tưởng Databinding bằng cách thay đổi trong phương thức ClassModel Khởi tạo của nó. (Chúng tôi chỉ đơn giản là sẽ thiết lập thuoojc tinhs cho một class mới ObservableCollection <ClassInfo> có chứa dữ liệu từ controller.)
ClassController.cs:
View Code:
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace ObjectDatabindingExample
{
public class ClassController
{
public void Initialize(ClassModel model)
{
this._model = model;

// The ObservableCollection’s constructor requires a List object. Because of this
// we have to wrap the ClassInfo array in a List.
this._model.Classes = new ObservableCollection<ClassInfo>(new List<ClassInfo>(this._data));
}

#region Private Members

private ClassModel _model;

private readonly ClassInfo[] _data = new ClassInfo[] {
new ClassInfo() { Name = “Calculus II” },
new ClassInfo() { Name = “Physics” },
new ClassInfo() { Name = “AI Algorithms and Design Considerations” },
new ClassInfo() { Name = “Programming Patterns” },
new ClassInfo() { Name = “Computer Networks” },
new ClassInfo() { Name = “Building and Programming Robots” },
new ClassInfo() { Name = “Distributed Systems” }
};

#endregion
}
}

Vì vậy, chúng ta có các dữ liệu liên kết được thực hiện, và controller được cập nhật theo mô hình một cách chính xác, tuy nhiên, chạy các ứng dụng cho thấy vẫn còn thiếu sót. Chúng ta không thấy bất kỳ items trong ListBox. Điều gì xảy ra đối với các đối tượng ClassModel không kể ClassView về controller thay đổi thuộc tính trong class trong suốt việc gọi để khởi tạo. Để khắc phục điều này, ClassModel phải thực hiện các giao diện INotifyPropertyChanged cho phép ClassView đăng ký các bản cập nhật cho các ClassModel. Khi bạn thiết lập các dữ liệu liên kết có vẻ như nếu đối tượng bị ràng buộc để thực hiện, giao diện này sẽ tự động được hiển thị
ClassModel.cs:
View Code:
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace ObjectDatabindingExample
{
public class ClassModel : INotifyPropertyChanged
{
public ObservableCollection<ClassInfo> Classes
{
get { return this._classes; }
set
{
this._classes = value;
this.sendPropertyChanged(“Classes”);
}
}

#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

#endregion

#region Private Members

private void sendPropertyChanged(string property)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}

private ObservableCollection<ClassInfo> _classes;

#endregion
}
}



Được rồi! đối tượng của chúng ta đang được hiển thị trong ListBox! Nhưng rõ ràng có một vấn đề. Các loại đối tượng đang được hiển thị, không phải là dữ liệu bên trong. Điều này không quan trọng ngoại trừ việc tôi nghĩ rằng chúng ta thay vì sẽ thấy dữ liệu mà phân biệt các đối tượng mỗi từ khác.
Vì vậy, chúng ta có một vấn đề với cách các đối tượng này đang được hiển thị. Hãy thay đổi cách hiển thị các đối tượng này ClassView ClassInfo bằng cách tạo ra một DataTemplate cho ListBox để áp dụng cho các item của nó. Để đơn giản chúng ta sẽ hiển thị từng item của một Label có nội dung liên kết với một thuộc tính Name. Thay đổi ClassView sau.
ClassView.xaml:
View Code:
<Window x:Class=”ObjectDatabindingExample.ClassView”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:local=”clr-namespace:ObjectDatabindingExample”
Title=”Object Data Binding Example” Height=”300″ Width=”300″ Loaded=”Window_Loaded”>

<Window.Resources>
<local:ClassModel x:Key=”model” />
</Window.Resources>

<Grid>

<ListBox ItemsSource=”{Binding Classes, Source={StaticResource model}}”>

<ListBox.ItemTemplate>

<DataTemplate>

<Label Content=”{Binding Name}” />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>

XAML này nói rằng chúng ta muốn thiết lập ItemTemplate của ListBox đến một DataTemplate, trong đó có một Labelnội dung liên kết với các thuộc tính Name của item mà template đang được áp dụng. Trong trường hợp của chúng ta dữ liệu template này đang được áp dụng cho từng đối tượng ClassInfo chứa ObservableCollection <ClassInfo>Các thuộc tính class của đối tượng ClassModel.

Bookmark and Share

0 comments:

Post a Comment

Next previous home

Cộng đồng yêu thiết kế Việt Nam Thiet ke website, danang