Blog chia sẽ kinh nghiệm lập trình và Technical VN. Nơi mà các bạn có thể học tập và tham khảo về những công nghệ mới nhất hiện nay về .NET
Thứ Bảy, 7 tháng 3, 2015
Trong bài viết Helloworld project chúng ta đã có class Bootstrapper đơn giản, song để dùng được IoC trong Caliburn.Micro chúng ta cần viết lại class này. Qua bài này chúng ta sẽ hiểu hơn về việc đặt tên cho một class trong Caliburn và cách dùng IoC...
I> IoC là gì
IoC viết tắc của Inversion Of Control, IoC là một khái niệm/mô hình/nguyên lý lớn trong việc phát triển những ứng dụng phức tạp, mục đích làm giảm sự phụ thuộc giữa các tầng, các thành phần và các lớp bằng cách nghịch đảo luồng điểu khiển của ứng dụng, chúng ta có thể hiểu rằng IoC là một nhà cung cấp(provider hay container), trong thực tế khi một Project lớn thì việc có nhiều Component, Module, Class... là bình thường song việc quản lý cũng như khởi tạo các đối tượng trên sẽ phức tạp dần theo quy mô dự án, vì thế IoC là giải pháp tối ưu cho việc quản lý, khởi tạo và cung cấp các đối tượng khi cần thiết .
Hai triển khai phổ biến của IoC là Dependency Injection (chống lại sự phụ thuộc) và Service location.

Thật tế, vấn đề quản lý việc tạo và hủy đối tượng với việc sử dụng IoC có lẽ cần một chút phép màu, vì rằng: ai sẽ giải phóng các đối tượng nếu bạn không chịu trách nhiệm khởi tạo chúng?
Điểm chính của một Framework là nó cung cấp IoC dưới dạng một thành-phần phần mềm gọi là Container. Giống như cái tên nó đã có ngụ ý, container sẽ biết những thành phần nào cần cho ứng dụng của bạn và cố gắng đủ thông minh để hiểu bạn muốn thành phần nào. Điều này xẩy ra khi bạn thực hiện một truy vấn và yêu cầu nó trả về một thành-phần mà nó là một trong những thực thể thường trú trong container . Đây chính là ý nghĩa của IoC. Sẽ không còn việc các Instance của lớp được tạo ra bằng cách sử dụng Constructor được định nghĩa sẳn trong lớp đó theo cách truyền thống(new A();). Thay vào đó chúng ta sẽ đăng ký chúng vào trong container và khi cần chung ta chỉ việc truy vấn container sau đó nó sẽ cho bạn một instance của thành phần mà bạn yêu cầu.
Đa phần IoC được các cộng đồng OpenSource phát triển là chính, Microsoft không chính thức phát tiển mô hình này cho nền tảng .NET(họ có cách khác tương tự về một số vấn đề Module) bởi vì về cơ bản nó vẫn là một điều mới mẻ và mơ hồ cho đa phần những người tiếp cận .NET. IoC đưa đến một cấu trúc tốt hơn, khả năng module hóa, khả năng kiểm lổi và bảo trì ứng ứng dụng tốt hơn. Một khi đã phát hiện ra điều này, các lập trình viên sẽ không bào giờ quay trở lại còn đường xưa cũ để xây dựng phần mềm.
II> Cấu hình Bootstrapper
Để dùng được IoC chúng ta cần phải quan tâm nhiều đến class Bootstrapper (xem và sử dụng lại Helloworld project), những class chúng ta muốn được IoC quản lý phải được Export, nếu class ấy là một trong nhiều implement cho một interface thì phải Export rõ ràng và khi GetInstance phải truy vấn với nhiều thông tin hơn. Ví dụ
[code language="csharp"]
internal interface IPage
{
}
// Implement của IPage
[Export("PageOne",typeof(IPage))]
internal class PageOne: IPage
{
}
[Export("PageTwo",typeof(IPage))]
internal class PageTwo: IPage
{
}
//------------------------------------
internal interface INews
{
}
// Implement của INews
[Export(typeof(INews))]
internal class News: INews
{
}
[/code]
class Bootstrapper.cs
[code language="csharp"]
internal sealed class Bootstrapper : BootstrapperBase
{
private CompositionContainer _container;
/// <summary>
/// Constructor
/// </summary>
public Bootstrapper()
{
StartRuntime();
}
/// <summary>
/// Override to configure the framework and setup your IoC container.
/// </summary>
protected override void Configure()
{
_container = new CompositionContainer(
new AggregateCatalog(AssemblySource.Instance.Select(x =>
new AssemblyCatalog(x)).OfType<ComposablePartCatalog>())
);
var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(_container);
_container.Compose(batch);
}
/// <summary>
/// Gets the instance.
/// </summary>
/// <param name="serviceType">Type of the service.</param>
/// <param name="key">The key.</param>
/// <returns></returns>
/// <exception cref="System.Exception"></exception>
protected override object GetInstance(Type serviceType, string key)
{
var contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = _container.GetExportedValues<object>(contract);
var enumerable = exports as object[] ?? exports.ToArray();
if (enumerable.Any())
return enumerable.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
/// <summary>
/// Gets all instances.
/// </summary>
/// <param name="serviceType">Type of the service.</param>
/// <returns></returns>
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
}
/// <summary>
/// Override this to provide an IoC specific implementation.
/// </summary>
/// <param name="instance">The instance to perform injection on.</param>
protected override void BuildUp(object instance)
{
_container.SatisfyImportsOnce(instance);
}
/// <summary>
/// Override this to add custom behavior to execute after the application starts.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The args.</param>
protected override void OnStartup(object sender, StartupEventArgs e)
{
base.OnStartup(sender, e);
DisplayRootViewFor<MainViewModel>();
}
}
[/code]
Đừng quên add reference "System.ComponentModel.Composition"
III> Sử dụng IoC
Tiến hành xây dựng phần sườn project
- Tạo một folder "Models"
- Tạo một interface "Models/IPage.cs"
- Tạo hai class implement cho interface "IPage" là "PageOne" và "PageTwo", tất cả ghi vào file "Models/Page.cs"
- Mở file "Views/MainView.xaml" và thêm vào hai TextBox và hai Button
- Thêm vào file "ViewModels/MainViewModels.cs" nội dung như dưới
Yêu cầu: Tôi có 2 TextBox lần lược hiển thị nội dung được Binding đến property "MainViewModel.Page" là "Page.Name" và "Page.Index", tùy và việc tôi nhấn vào Button "PageOne" hay "PageTwo" mà nội dung hiển thị được thay đổi. Các bạn chú ý rằng không hề có việc tôi new một thể hiện của interface"IPage" và gán cho property "MainViewModel.Page" ở code dưới vì tôi dùng IoC để new một class.
MainViewModel.cs
[code language="csharp"]
[Export(typeof(MainViewModel))]
internal class MainViewModel : INotifyPropertyChanged
{
private IPage _page;
public IPage Page
{
set
{
_page = value;
OnPropertyChanged("Page");
}
get { return _page; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Constructor
/// </summary>
public MainViewModel()
{
}
/// <summary>
/// Show PageOnr
/// </summary>
public void PageOne()
{
Page = IoC.Get<IPage>("PageOne");
}
/// <summary>
/// Show PageTwo
/// </summary>
public void PageTwo()
{
Page = IoC.Get<IPage>("PageTwo");
}
}
[/code]
IPage.cs
[code language="csharp"]
internal interface IPage
{
/// <summary>
/// Dislay name
/// </summary>
string Name { set; get; }
/// <summary>
/// Number of it
/// </summary>
int Index { set; get; }
}
[/code]
Page.cs
[code language="csharp"]
[Export("PageOne",typeof(IPage))]
internal class PageOne: IPage
{
private string _name = string.Empty;
private int _index;
/// <summary>
/// Dislay name
/// </summary>
public string Name
{
set { _name = value; }
get { return _name; }
}
/// <summary>
/// Number of it
/// </summary>
public int Index
{
get { return _index; }
set { _index = value; }
}
public PageOne()
{
Name = "PageOne";
Index = new Random().Next(100);
}
}
[Export("PageTwo",typeof(IPage))]
internal class PageTwo: IPage
{
private string _name = string.Empty;
private int _index;
/// <summary>
/// Dislay name
/// </summary>
public string Name
{
set { _name = value; }
get { return _name; }
}
/// <summary>
/// Number of it
/// </summary>
public int Index
{
get { return _index; }
set { _index = value; }
}
public PageTwo()
{
Name = "PageTwo";
Index = new Random().Next(100);
}
}
[/code]
MainView.xaml
[code language="xml"]
<Window x:Class="HelloWorl.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainView" Height="200" Width="300">
<Grid>
<StackPanel Margin="10,20,10,50" Orientation="Vertical" VerticalAlignment="Top">
<TextBox x:Name="Name" Height="21"
Text="{Binding Page.Name, UpdateSourceTrigger=PropertyChanged}"
BorderBrush="#FF3399FF" Margin="0,1" />
<TextBox x:Name="Index" Height="21"
Text="{Binding Page.Index, UpdateSourceTrigger=PropertyChanged}"
BorderBrush="#FF3399FF" Margin="0,1" />
</StackPanel>
<StackPanel VerticalAlignment="Bottom" Margin="0,0,0,20">
<Button Content="PageOne" x:Name="PageOne" Height="21"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Padding="2,1,5,1" MaxWidth="100" MinWidth="100" Margin="0,1"
Background="#FF3399FF" Foreground="White"/>
<Button Content="PageTwo" x:Name="PageTwo" Height="21"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Padding="2,1,5,1" MaxWidth="100" MinWidth="100" Margin="0,1"
Background="#FF3399FF" Foreground="White" />
</StackPanel>
</Grid>
</Window>
[/code]
Kết quả là
Tải sourcecode tại đây, chúc các bạn thành công,
Phạm Tuân
Search
Popular Posts
-
Phong cách thiết kế Material Design nhắm đến những đường nét đơn giản, sử dụng nhiều mảng màu đậm nổi bật, các đối tượng đồ họa trong giao ...
-
Hôm nay tôi sẽ giới thiệu với các bạn một Framework đến từ Microsoft - framework này không quá lớn nhưng là khá mạnh khi các bạn làm việc vớ...
-
WPF vượt trội hơn Winform về khoản Drawing , trong đó đặc biệt WPF hỗ trợ đồ họa rất tốt vì nó tương tác trực tiếp đến GPU. Hôm nay chúng t...
-
Hôm nay chúng ta sẽ tìm hiểu cách tạo ra các menu chuột phải trên ứng dụng WPF của mình. Ở bài này chúng ta xoay quanh việc tìm hiểu cách tạ...
-
Để dễ hiểu, các bạn hãy hình dung rằng: cùng một tập tin thực thi *.EXE nhưng bạn DoubleClick 10 lần cách quãng vào nó thì chuyện gì sẽ sảy ...
-
Trong bài viết trước tôi có giới thiệu về Extension Methods trong nguôn ngữ lập trình C#; hôm nay tôi sẽ nói về một vấn đề có ý nghĩa tương...
-
Hôm nay chúng ta sẽ thử đo xem thời gian query Data của "Foreach vs LinQ vs LinQasParallel" như thế nào. Tôi tạo một tool nhỏ để l...
-
Data Binding là kĩ thuật dùng để tạo gắn kết giữa phần giao diện ( UI ) và dữ liệu thông qua phần business logic hoặc giữa các đối tượng UI...
-
LOG4NET là một thư viện mã nguồn mở cho phép chúng ta tạo ra một hoặc nhiều tập tin log, kiểu log cũng như nội dung log một cách linh hoạt v...
-
Sau hai bài giới thiệu về Caliburn.Micro framework, hôm nay chúng ta sẽ cùng bắt tay vào làm một dự án nhỏ - HelloWorld. Step 1: Add referen...
Recent Posts
Blog Archive
-
▼
2015
(48)
-
▼
tháng 3
(12)
- WPF Training - Drag and Drop Trong WPF Part I
- C# - Khi Nào Nên Dùng Lớp Parallel
- WPF - Xây Dựng Ứng Dụng WPF Metro Với Thư Viện Mah...
- WPF Styles - ToggleButton Switch Phong Cách IOS
- C# - Tìm Hiểu Về MEF Trong Lập Trình C#
- C# - Kiểm Tra Tốc Độ Của Foreach vs LinQ vs LinQas...
- WPF vs Caliburn - IoC Là Gì Và Cấu Hình Bootstrapp...
- WPF vs Caliburn - Bắt Đầu HelloWorld Project Cùng ...
- WPF vs Caliburn- Tìm Hiểu Về Caliburn.Micro Framew...
- WPF vs Caliburn- Tìm Hiểu Về Caliburn.Micro Framew...
- Log4net - Configuration log4net Nâng Cao (các filt...
- WPF Training - How To Binding RadioButton Group
-
▼
tháng 3
(12)
0 nhận xét:
Đăng nhận xét