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
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
Chủ Nhật, 1 tháng 2, 2015
Sau Dependency property, chúng ta sẽ tiếp tục tìm hiểu về Attached property - một loại property không thuộc đối tượng trực tiếp sử dụng nó(khác Dependency property). Dễ hiểu hơn có nghĩa là property này được định nghĩa ở một class/object khác và được dùng như một property của class/object này(na ná cách dùng của Extension methods), bởi thế mới gọi là Attached.
Bạn có thể thấy một số Attached property khi sử dụng các panel: Dock, Grid, Canvas ... Trong ví dụ dưới đây, chúng ta set giá trị DockPanel.Dock cho TextBox là "Top", xong property Dock lại không phải là một property thuộc TextBox - đó là một Attached property được định nghĩa ở DockPanel, attached property này dùng cho tất cả các control đang được chứa bởi DockPanel.
[code language="xml"]
<TextBox DockPanel.Dock=”Top”>Attached property</TextBox>
[/code]
Để tạo một attached property chúng ta phải tuân theo cấu trúc này( hãy liên tưởng đến bài Dependency property trước để có sự so sánh về cách đăng ký một attached property - không khéo là nhầm lẫn đấy)
[code language="csharp"]
public class RotationManager
{
public static propertyType Get[+ propertyName](DependencyObject obj)
{
//TODO: need to implement now
return (propertyType)obj.GetValue([propertyName+]Property);
}
public static void Set[+ propertyName](DependencyObject obj, propertyType value)
{
//TODO: need to implement now
obj.SetValue([propertyName+]Property, value);
}
public static readonly DependencyProperty [propertyName+]Property =
DependencyProperty.RegisterAttached("propertyName",
typeof(propertyType), typeof(ownerType),
new [defaultMetadata](0.5, [propertyChangedCallback]));
private static void propertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
//TODO: need to implement now
}
}
[/code]
Diễn gải:
- propertyName: Là tên của property bạn muốn tạo ví dụ "Dock"
- propertyType: Là Type mà attached property này nhận
- ownerType: là Type của đối tượng chịu trách nhiệm(Owner) property này, ví dụ DockPanel
- propertyChangedCallback: là hàm sẽ được gọi khi Value của attached property bị thay đổi
- defaultMetadata: là một object thuộc PropertyMetadata - chỉ loại các đối tượng sẽ được thừa hưởng property này
- FrameworkPropertyMetadata: tất cả các element trong XAML
- UIPropertyMetadata: là các UI element/Control trong XAML
Ví dụ trực quan: Tôi có một Path, tôi xoay nó với góc 50 độ và được như hình sau
XAML thế này
[code language="xml"]
<Grid Background="White" Margin="25">
<Path Stretch="Uniform" Fill="#FF08578B" Data="F1 M 28.4583,20.8296C 28.9254,20.4138 29.2514,19.768 29.4364,18.8921C 29.6214,18.0162 29.4554,17.0984 28.9384,16.1389C 29.3694,14.16 29.0234,12.7686 27.9003,11.9646C 26.7772,11.1607 25.4592,10.7729 23.946,10.8015L 23.274,10.8015C 23.614,10.1266 23.882,9.40756 24.0781,8.64438C 24.2741,7.8812 24.3741,7.20871 24.3781,6.62686C 24.3166,4.37555 23.8036,2.70673 22.839,1.62039C 21.8744,0.534058 20.8272,-0.006073 19.6976,0C 17.6181,0.0614014 16.274,1.37863 15.6653,3.95166C 15.6406,4.27734 15.1563,5.48642 14.2124,7.57889C 13.2686,9.67136 11.8711,11.4226 10.02,12.8326L 10.02,11.6045C 9.94067,10.959 9.57507,10.5968 8.92316,10.5181L 1.0975,10.5181C 0.445374,10.5968 0.0795288,10.959 0,11.6045L 0,30.0051C 0.0795288,30.7017 0.445374,31.086 1.0975,31.1581L 8.92316,31.1581C 9.57507,31.086 9.94067,30.7017 10.02,30.0051L 10.02,27.7953C 10.7491,28.3628 12.6754,28.989 15.7988,29.6737C 18.9222,30.3584 21.8093,30.4828 24.46,30.0469C 27.1107,29.6109 28.0914,27.9957 27.4023,25.2011C 28.0253,24.7488 28.4593,24.1283 28.7043,23.3396C 28.9493,22.551 28.8674,21.7143 28.4583,20.8296 Z M 24.2341,20.7815C 25.4911,21.0257 26.0372,21.5341 25.8722,22.3068C 25.7072,23.0794 24.7771,23.5158 23.082,23.6158C 22.812,23.6399 22.68,23.748 22.686,23.9401C 22.692,24.1323 22.872,24.2644 23.226,24.3365C 24.8361,24.7918 25.4081,25.4303 24.9421,26.252C 24.4761,27.0737 23.392,27.5081 21.6899,27.5551C 20.587,27.5541 19.0097,27.388 16.9579,27.0567C 14.9062,26.7254 12.5936,25.9468 10.02,24.7208L 10.02,16.0445C 11.9097,15.114 13.6807,13.4388 15.3332,11.0186C 16.9857,8.59857 17.9977,6.34018 18.3693,4.2435C 18.4157,3.81894 18.5482,3.46432 18.7666,3.17972C 18.985,2.89514 19.2953,2.74728 19.6976,2.73615C 20.1107,2.74524 20.5296,3.09171 20.9543,3.77557C 21.3792,4.45944 21.6083,5.42606 21.6419,6.67551C 21.5589,7.68878 21.227,8.72198 20.646,9.77512C 20.0651,10.8282 19.7331,11.6585 19.6501,12.2657C 19.6491,12.525 19.7697,12.765 20.0118,12.9858C 20.254,13.2066 20.6236,13.324 21.1207,13.3381L 23.946,13.3381C 25.3041,13.4708 26.0562,14.0019 26.2022,14.9312C 26.3482,15.8606 25.8042,16.3916 24.5701,16.5244C 24.3061,16.5867 24.1741,16.7006 24.1741,16.8661C 24.1741,17.0316 24.3061,17.1356 24.5701,17.1781C 25.8192,17.3445 26.4172,17.853 26.3642,18.7038C 26.3112,19.5545 25.6012,20.0389 24.2341,20.157C 23.9221,20.177 23.7661,20.2691 23.7661,20.4332C 23.7661,20.5974 23.9221,20.7135 24.2341,20.7815 Z "
RenderTransformOrigin="0.5,0.5">
<!-- Xoay -->
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="50"/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
[/code]
Chú ý rằng tôi xoay Path trên nhờ đoạn XAML sau
[code language="xml"]
<Path Stretch="Uniform" Fill="#FF08578B" Data="............."
RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="50"/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path></pre>
<pre>[/code]
Nhưng tôi thấy nó quá dài - đến vài thẻ XAML cho một giá trị Angle="50", nếu tôi dùng phép xoay này nhiều lần trong một file XAML hoặc nhiều file XAML khác thì thật rối mắt, vậy nên tôi tạo ra một attached property thay thế đoạn XAML kia như sau
[code language="csharp"]
public class RotationManager
{
/// <summary>
/// Get giá trị của attached property
/// </summary>
/// <param name="obj">Đối tượng Dependency</param>
/// <returns>Giá trị của attached property</returns>
public static double GetAngle(DependencyObject obj)
{
return (double)obj.GetValue(AngleProperty);
}
/// <summary>
/// Set giá trị góc cho đối tượng
/// </summary>
/// <param name="obj">Đối tượng Dependency</param>
/// <param name="value">Giá trị do user input</param>
public static void SetAngle(DependencyObject obj, double value)
{
obj.SetValue(AngleProperty, value);
throw new NoNullAllowedException();
}
public static readonly DependencyProperty AngleProperty =
DependencyProperty.RegisterAttached("Angle",
typeof(double), typeof(RotationManager),
new UIPropertyMetadata(0.5, OnAngleChanged));
/// <summary>
/// CallBack khi value của property thay đổi
/// </summary>
/// <param name="obj">Đối tượng Dependency</param>
/// <param name="e"></param>
private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var element = obj as UIElement;
if (element != null)
{
element.RenderTransformOrigin = new Point(.5, .5);
element.RenderTransform = new RotateTransform((double)e.NewValue);
}
}
}
[/code]
Và dùng đơn giản thế này, tôi tiến hành xoay góc 180 độ
[code language="xml"]
<Grid Background="White" Margin="25">
<Path Stretch="Uniform" Fill="#FF08578B" Data="Như củ" RenderTransformOrigin="0.5,0.5"
local:RotationManager.Angle="180"/>
</Grid>
[/code]
Hãy so sánh với đoạn code trước
[code language="xml"]
<!-- khi không dùng attached property -->
<Path Stretch="Uniform" Fill="#FF08578B" Data="............."
RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="50"/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
<!-- khi dùng attached property thì code chỉ thế này -->
<Path Stretch="Uniform" Fill="#FF08578B" Data="............."
RenderTransformOrigin="0.5,0.5"
local:RotationManager.Angle="180"/>
[/code]
Kết quả
Chúc mọi người thành công!
Phạm Tuân
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 ...
