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, 4 tháng 4, 2015
Sau bài "WPF Training – Drag and Drop Trong WPF Part I" nói về Drag-Drop, bài tiếp theo tôi xin nói về một Library hỗ trợ việc này theo hướng đơn giản mà hiệu quả cũng như không kém phần đẹp mắt và tùy biến.
I> Tiếp cận
Thư viện GongSolutions.Wpf.DragDrop là một sự nỗi bậc trong vấn đề Implement Drag-Drop WPF. Thư viện này có một số điểm nỗi bậc như sau:
- Hỗ trợ phát triển với mô hình MVVM, có nghĩa là phần Behavior có thể được đặc trong một ViewModel thay vì CodeBehind.
- Có nhiều sự lựa chọn khi sử dụng, hỗ trợ cả về vấn đề Drag-Drop phục vụ cho việc thay đổi Index
- Có thể làm việc với TreeViews
- Cho phép tùy chọn mặc định hoặc tự định nghĩa cách thể hiện trực quan cho Drag-Drop.
Các bạn có thể tham khảo Source tại đây
II> Ứng dụng mẫu
Công việc của bạn là tạo một project WPF Application và add reference thư viện tải ở trên. Sau đó thiết kế project theo mô hình MVVM cơ bản; hai View và một ViewModels. cấu trúc project như này:

Chúng ta chỉ cần quan tâm đến hai file. "ListBoxDDView.xaml" là phần View của ListBox với chức năng Drag-Drop với DataContext là "ListBoxDDViewModel.cs". Ngoài ra, "MainWindowVew" là View chính chứa 2 "ListBoxDDView" và "PerItem.cs" chính là class thể hiện một Item trong ListBox.
PerItem.cs
[code language="csharp"]
public class PerItem
{
public string Name { set; get; }
public PerItem(string name)
{
Name = "Item: " + name;
}
}
[/code]
Design phần View với code như sau(xem về DataTemplate để hiểu)
ListBoxDDView.xaml
[code language="xml"]
<Grid>
<ListBox ItemsSource="{Binding DataCollection, UpdateSourceTrigger=PropertyChanged}"
Foreground="White"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Margin="2,2,2,2" TextWrapping="Wrap" IsReadOnly="True"
Text="{Binding Name}" VerticalAlignment="Top" VerticalContentAlignment="Center"
BorderBrush="#FF007ACC" Template="{DynamicResource TextBoxBaseTemplate}"
Background="{x:Null}" Padding="0,2"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
[/code]
Sau đó chúng ta thêm Attach Property vào code trên để dùng được Drag-Drop
[code language="xml"]
<Grid>
<ListBox ItemsSource="{Binding DataCollection, UpdateSourceTrigger=PropertyChanged}"
DragDrop:DragDrop.DropHandler="{Binding}"
DragDrop:DragDrop.IsDragSource="True"
DragDrop:DragDrop.IsDropTarget="True"
Foreground="White"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Margin="2,2,2,2" TextWrapping="Wrap" IsReadOnly="True"
Text="{Binding Name}" VerticalAlignment="Top" VerticalContentAlignment="Center"
BorderBrush="#FF007ACC" Template="{DynamicResource TextBoxBaseTemplate}"
Background="{x:Null}" Padding="0,2"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
[/code]
Chú ý:
- Để dùng được Attached Property trên ta cần reference thư viện <xmlns:DragDrop="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop">
- DragDrop.DropHandler="{Binding}" chỉ ra method sẽ implement cho việc Drop data
- DragDrop.IsDragSource="True" nói rằng Control là nguồn Drag(tức có thể kéo Item của nó)
và nó sẽ gọi implement của method Drag - DragDrop.IsDropTarget="True" ý rằng Control này cho phép Drag data vào nó sẽ gọi implement của method Drop
Sau đó implement cho phần VewModel, model này implement của interface IDropTarget
ListBoxDDViewModel.cs
[code language="csharp"]
public class ListBoxExViewModel : IDropTarget
{
public ObservableCollection<PerItem> DataCollection { set; get; }
public bool IsAllowMove { set; get; }
public ListBoxExViewModel()
{
DataCollection = new ObservableCollection<PerItem>();
for (int i = 0; i < 20; i++) {
DataCollection.Add(new PerItem(i.ToString()));
}
}
// Được gọi khi bạn Kéo một Item đi
public void DragOver(IDropInfo dropInfo)
{
if (IsAllowMove)
{
// Hiệu ứng Drag
dropInfo.Effects = DragDropEffects.Move;
}
else
{
// Hiệu ứng Drag
dropInfo.Effects = DragDropEffects.Copy;
}
// Hiệu ứng Drop
dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
}
// Được gọi khi một Item được Drag lên một Control cho phép Drop
public void Drop(IDropInfo dropInfo)
{
var data = dropInfo.Data as PerItem;
// Lấy data và xử lý
if (data != null)
{
DataCollection.Add(data);
var source = dropInfo.TargetCollection;
}
else
{
var dataList = dropInfo.Data as IList<PerItem>;
if (dataList != null && dataList.Count > 0)
{
foreach (PerItem perItem in dataList)
{
DataCollection.Add(perItem);
}
}
}
}
}
[/code]
Chú ý: các bạn có thể implement interface IDragSource để có nhiều xử lý hơn khi Drag
Kết quả
Để đẹp hơn chúng ta cần thêm đoạn code sau vào phần View( vào thẻ ListBox trong ListBoxDDDView.xaml)- Hiệu ứng kèm theo chuột cho các Item được Drag: DragDrop:DragDrop.UseDefaultDragAdorner="True" [1]
- Hiệu ứng chú thích/ hiệu ứng Drag của chuột: DragDrop:DragDrop.UseDefaultEffectDataTemplate="True"
- Thêm hiệu ứng kèm theo chuột cho các Item được Drap: DragDrop:DragDrop.DragAdornerTemplate="{StaticResource DragAdorner}" với DragAdorner là một Template do bạn tạo(không dùng chung với [1]).
- Và còn nhiều tùy chọn khác bạn có thể tìm hiểu ......
Source tham khảo tại đây. Chúc các bạn thành công!
Phạm Tuân
Chủ Nhật, 15 tháng 3, 2015
Chào các bạn, hôm nay tôi sẽ giới thiệu đến mọi người về một thư viện khác giúp chúng ta xây dựng một ứng dụng WPF với giao diện mang đậm phong cách thiết kế của Window 8 đó là giao diện Metro.
I> Tiếp cận
MahApps.Metro là một dự án được Paul Jenkins bắt đầu phát triển vào năm 2011, nhầm mang một giao diện người dùng Metro-style vào ứng dụng WPF. Kể từ đó nó được phát triển và nhận được nhiều đóng góp từ cộng đồng nguồn mở cho đến bây giờ. Đây là một dự án vì cộng đồng, do cộng đồng - không ai trong số họ được trả tiền để làm điều này, song sản phẩm mà học tạo ra thật sự đã thay đổi được nhiều thứ.
Vậy bạn có thể tải về bộ thư viện này ở đâu? Cách đơn giản nhất là dùng NuGet
[code language="c"]
Install-Package MahApps.Metro
[/code]
Hoặc có thể tải trọn bộ mã nguồn tại Github, mời các bạn xem qua một số hình ảnh
II> Ứng dụng mẫu
Trước tiên chúng ta cần tạo một project WPF và add reference các thư viện cần thiết, hãy bắt đầu với NuGet nếu bạn cảm thấy bối rối về việc tải và add reference
Xong phần add DLLs chúng ta tiến hành tải về phần Resource của thư viện này(bạn có thể tải hoặc không tùy thích nhưng để hiểu nó làm việc thể nào thì đừng bỏ qua bước này) như hình sau.
Tool -> NuGet Package Panager -> Manage NuGet Packages For Solution
Chọn và tải về MahApps.Metro.Resource; đừng quên mục "Include Prerelease:
Hoặc bạn không thể tải resource như cách trên thì có thể dùng NuGet
[code language="c"]
Install-Package MahApps.Metro -Pre
[/code]
Chạy ứng dụng xem điều gì đã sảy ra và tiếp tục sửa nội dung các file XAML, mở file "MainWindow.xaml" thêm namespace của MahApps.Metro vào trong thẻ <Window ...>
[code language="csharp"]
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
// Hoặc
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
[/code]
Tiếp theo thay thẻ Window bằng thẻ của MahApps, file hoàn thiện sẽ là như sau nhưng đừng có coppy hết vào ứng dụng của bạn mà quên đổi namespace "x:Class="WpfApplication1.MainWindow"
[code language="xml"]
<Controls:MetroWindow x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="MainWindow"
Height="350"
Width="525">
<!-- Tiếp tục code tại đây -->
</Controls:MetroWindow>
[/code]
Mở tiếp file MainWindow.xaml.cs và thay đổi lớp kế thừa của MainWindow
[code language="csharp"]
// using statements...
using MahApps.Metro.Controls
public partial class MainWindow : MetroWindow
{
public MainWindow()
{
InitializeComponent();
}
}
[/code]
Tạm thời đã xong về cơ bản, để đẹp hơn chúng ta dùng Resource của MahApps, mở file App.xaml lên và thêm ResourceDistionary
[code language="xml"]
<Application <!--........--> >
<!--Phần cần thêm-->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<ResourceDictionary Source="Resources/Icons.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<!--Phần cần thêm-->
</Application>
[/code]
Kết quả,Để thêm một vài lệnh lên trên Titlebar chúng ta mở file MainWindow.xaml và thêm đoạn code dưới đây vào ngay sau thẻ <Controls:MetroWindow ... > thêm vào đây... </Controls:MetroWindow>
[code language="xml"]
<Controls:MetroWindow ... >
<Controls:MetroWindow.RightWindowCommands>
<Controls:WindowCommands>
<Button Content="Cài đặt" />
<Button>
<StackPanel Orientation="Horizontal">
<Rectangle Width="20" Height="20"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button},
Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill"
Visual="{StaticResource appbar_windowsphone}" />
</Rectangle.OpacityMask>
</Rectangle>
<TextBlock Margin="4 0 0 0"
VerticalAlignment="Center"
Text="Phạm Tuân" />
</StackPanel>
</Button>
</Controls:WindowCommands>
</Controls:MetroWindow.RightWindowCommands>
<Grid>
</Grid>
</Controls:MetroWindow>
[/code]
Thế là xong, mời các bạn tải về tham khảo tại đây và đọc thêm tại đây
Phạm Tuân
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
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 reference
Khi đã tạo xong một project WPF Application, chúng ta sẽ phải tải về các DLLs của Caliburn và add vào project hoặc làm việc này tự động bằng cách mở "Package Manager Console" và paste command dưới đây vào rồi Enter.
TOOL -> NuGet Package Manager -> Package Manager Console
[code language="html"]
Install-Package Caliburn.Micro
[/code]
Step 2: Tổ chức lại project
- Xóa 2 file MainWindow.*
- Xóa dòng StartupUri="MainWindow.xaml" trong file App.xaml
- Tạo mới 2 folder với tên lần lược là "Views" và "ViewModels"

Step 3: Xây dựng
- Tạo class Bootstrapper.cs
- Tạo class "ViewModels/MainViewModel.cs" và tạo một Window "Views/MainView.xaml"
- Xóa file "Views/MainView.cs"
- Changed nội dung các file "App.xaml", "App.cs" như sau
App.xaml
[code language="xml"]
<Application x:Class="HelloWorl.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helloWorl="clr-namespace:HelloWorl">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<helloWorl:Bootstrapper x:Key="bootstrapperex" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
[/code]
App.cs
[code language="csharp"]
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
/// <summary>
/// Constructor
/// </summary>
public App()
{
InitializeComponent();
}
}
[/code]
Bootstrapper.cs
[code language="csharp"]
internal class Bootstrapper: BootstrapperBase
{
/// <summary>
/// Constructor
/// </summary>
public Bootstrapper()
{
this.StartRuntime();
}
/// <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);
// MainViewModel sẽ được hiểu là Datacontent của MainView
// Dòng dưới chỉ ra một View chính cho App
DisplayRootViewFor<MainViewModel>();
}
}
[/code]
Ta có project như sau

Đến đây chúng ta đã xong phần Helloworld, F5 và nhận kết quả, tải sourcecode tại đây (vì các DLLs đã được xóa nên hãy mở mạng và Rebuild project để NuGet tải lại dll).
Vậy mời các bạn đón xem phần tiếp theo!
Phạm Tuân
Thứ Năm, 5 tháng 3, 2015
Như ở bài trước tôi đã giới thiệu về caliburn.mocro, bài tiếp theo này tôi sẽ hướng dẫn các bạn về cách tạo một project WPF hợp chuẩn mô hình MVVM(*) dùng Caliburn framework. Bài này cho ta cái nhìn cơ bản về cấu trúc một Project WPF-Caliburn...
I> Hiểu MVVM Là Gì
Để tổ chức một project theo mô hình MVVM nói chung và Caliburn nói riêng chúng ta cần hiểu rõ MVVM là gì và cơ chế Mapping(View - ViewModel) mà Framework hiện tại hỗ trợ. Hai hình sau minh họa khã rõ mô hình MVVM


Class diagram

.gif)
II> Quy Ước Tổ Chức Một Project Của Caliburn

Theo quy ước của Caliburn, phần View-ViewModel-Model phải được đặt tên theo một quy ước để có thể tận dụng tối hiệu năng của framework - mà dễ thấy nhất đó là một View sẽ được tự động kết dính với một ViewModel( bạn sẽ có cơ hội cảm nhận về điều này sau) nếu bạn tuân các thủ quy ước sau.
| View Model | View | |
|---|---|---|
| Convention | <EntityName>ViewModel | <EntityName>View |
| Example 1 | ShellViewModel | ShellView |
| Example 2 | TabViewModel | TabView |
Vì View trong thực tế được thể hiện như một Page nên chúng ta hoàn toàn có thể đặt tên như bảng dưới đây
| View Model | View | |
|---|---|---|
| Convention | <EntityName>PageViewModel | <EntityName>Page |
| Example 1 | MainPageViewModel | MainPage |
| Example 2 | OrderPageViewModel | OrderPage |
Nếu chúng ta có một Namespace khá dài cho các ViewModel hoặc View, chúng ta phải tuân thủ cách đặt tên sau
| View Model | View | |
|---|---|---|
| Convention | <RootNS>.<ViewModelTypeName> | <RootNS>.<ViewTypeName> |
| Example 1 | MyProject.ShellViewModel | MyProject.ShellView |
| Example 2 | MyProject.MainPageViewModel | MyProject.MainPage |
Hoặc
| View Model | View | |
|---|---|---|
| Convention | <RootNS>.ViewModels.<ChildNS>.<ViewModelTypeName> | <RootNS>.Views.<ChildNS>.<ViewTypeName> |
| Example 1 | MyProject.ViewModels.ShellViewModel | MyProject.Views.ShellView |
| Example 2 | MyProject.ViewModels.Utilities.SettingsViewModel | MyPoject.Views.Utitlities.SettingsView |
Dưới đây là một ví dụ về cách tổ chức một project Caliburn.Micro

Hay
Tất cả những quy ước trên là bạn phải thực hiện chính xác nếu muốn tận dụng nhiều tính năng hay, song bạn hoàn toàn có thể thay đổi theo ý cá nhân vì đây là framework mã nguồn mở.
-----------------------------------------------------------------
- Tìm Hiểu Về Caliburn.Micro Framework Phần I
- Tìm Hiểu Về Caliburn.Micro Framework Phần II
Thứ Tư, 4 tháng 3, 2015
Caliburn.Micro Framework được những người phát triển nó nói một cách khiêm tốn là một Framework nhỏ bé nhưng cộng đồng Dev lại thấy rằng nó vô cùng mạnh mẽ. Framework này được thiết kế cho việc phát triển các ứng dụng xây dựng trên tất cả các nền tảng XAML(WPF, Silverlight, Windows Phone, Windows 8...). Hỗ trợ mạnh cho mô hình MV *, cho phép xây dựng các giải pháp của bạn một cách nhanh chóng, và bền vững.
I> Tính năng nỗi bật
Binding đơn giản từ View xuống ViewModel với x:Name, giảm thời gian thiết kế
*.XAML
[code language="xml"]
<ListBox x:Name="Products" />
[/code]
*.CS
[code language="csharp"]
// View sẽ được tự động binding đến property bênh dưới
public BindableCollection<ProductViewModel> Products
{
get; private set;
}
public ProductViewModel SelectedProduct
{
get { return _selectedProduct; }
set
{
_selectedProduct = value;
NotifyOfPropertyChange(() => SelectedProduct);
}
}
[/code]
Tự động Binding một Method với hành xử của View kèm các đối số tự động maping theo x:Name
*.XAML
[code language="xml"]
<StackPanel>
<TextBox x:Name="Username" />
<PasswordBox x:Name="Password" />
<Button x:Name="Login" Content="Log in" />
</StackPanel>
[/code]
*.CS
[code language="csharp"]
// Hàm trả giá trị cho biết có thể thực hiện Login command hay không
public bool CanLogin(string username, string password)
{
return !String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password);
}
// Hàm dưới được thực hiện với sự kiện Click của Button theo kiểu Command
// Các param sẽ được lấy giá trị từ View với name tương ứng paramName
public string Login(string username, string password)
{
// Do somethings...
}
[/code]
Ngoài ra Caliburn còn nhiều tính năng khác mạnh mẽ và thuận tiện hơn khi làm việc với mô hình MV*. Trong mô hình MVVM có sử dụng Caliburn chúng ta sẽ tuân thủ một số cấu trúc cho một project WPF-MVVM như sau( [*] ý chỉ là bất kỳ một ký tự hợp lệ nào nhập từ bàn phím)
- Các thành phần View(tức code XAML thể hiện một Window hoặc UserControl hoặc Page...) được đặc chung vào thư mục cha là "*View" hoặc "*Views"
- Các thành phần ViewModel(tức phần logic *.cs cho View tương ứng) được đặc trong cùng một thư mục cha là "*ViewMode" hoặc "*ViewModels"
II> Bắt đầu cùng Caliburn

Để khởi đầu một dự án với Caliburn.Micro trước tiên chúng ta cần tải thư viện này về theo hai cách thông dụng
- Dùng Nuget với command = "PM> Install-Package Caliburn.Micro", dán code này vào Tool->...->Package Manager Console
- Download trược tiếp từ codeplex với link
Thứ quan trọng nhất và là xương sống của Caliburn.Midro cũng như các MVVMFramework khác là Bootstrapper và IoC ngoài ra chúng ta có thể đọc thêm tại trang chủ Caliburn về các thành phần quan trọng trong framework này. Tôi sẽ sớm có nhiều bài viết về chủ đề liên quan cho người mới bắt đầu tìm hiểu về WPF-MVVM có dùng Caliburn.
-----------------------------------------------------------------
- Tìm Hiểu Về Caliburn.Micro Framework Phần I
- Tìm Hiểu Về Caliburn.Micro Framework Phần II
Chúc các bạn vui vẻ,
Tuân Phạm
Search
Popular Posts
-
Để 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 ...
-
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 ...
-
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...
-
ReSharper là một công cụ Add-on cho Visual Studio, nó giúp lập trình viên tốn ít thời gian cho việc xem xét định dạng code, phong cách code,...
-
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ạ...
-
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ớ...
-
Một khía cạnh hết sức quan trọng trong WPF đó là Trigger - Trigger giúp nắm bắt được mọi thay đổi trong một hệ thống GUI của WPF. Nhờ có Tr...
-
Như ở bài trước tôi đã giới thiệu về caliburn.mocro, bài tiếp theo này tôi sẽ hướng dẫn các bạn về cách tạo một project WPF hợp chuẩn mô hìn...
-
Khi các bạn làm một dự án khá lớn, nhu cầu tạo ra các Custom Control là không tránh khỏi, trong WinForm hay WPF đều cho phép chúng ta tạo r...
-
Hôm nay tôi sẽ giới thiệu đến các bạn một thư viện mã nguồn mở, nó là gì? Đơn giản là một thư viện với TabControl được Custom lại với nhiều ...
