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, 28 tháng 3, 2015
Đối với lập trình hiện đại hiện nay, việc hỗ trợ người dùng tối đa cũng như trừu tượng hóa các công việc đến mức gần gủi và dễ hiểu nhất cho người dùng đang là tiêu chí hàng đầu của các nhà phát triển phần mềm, chúng ta có thể thấy lợi ích từ việc mà các ứng dụng hộ trợ Drag-and-Drop, công việc trở nên đơn giản hơn và chân thật hơn, thao tác kéo thả nói lên nhiều ý nghĩa hơn việc nhấn các Button. Và hôm nay, tôi sẽ hướng dẫn cở bản cho việc Implement Drag-and-Drop trong WPF.
WPF Training - Drag and Drop Trong WPF Part II...
I> Design UI
Công việc rất đơn giản, chúng ta cần chuẩn bị những thứ như sau
- WrapPanel A: nguồn chứa đối tượng - Drag
- WrapPanel B: nguồn nhận đối tượng - Drop
- Ellipse: Đối tượng được drag-drop
Chúng ta Design như sau
[code language="xml"]
<WrapPanel x:Name="_target" Drop="UIElement_OnDrop" AllowDrop="True"
Background="Chartreuse"/>
<WrapPanel x:Name="_source" MouseMove="MouseMove" Grid.Column="2">
[/code]
Trong đó,
- "UIElement_OnDrop" là method sẽ được call khi có đối tượng đang được Drag lên _target Panel
- "MouseMove" là method xử lý cho việc Drag, chúng ta có thể dùng ở nhiều sự kiện khác cũng được như MouseLeftButtonDown="MouseMove".
II> Implement behavior
Chúng ta tiến hành implement cho hai method trên như sau
[code language="csharp"]
#region
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
#endregion
namespace Drag_Drop_Sample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MouseMove(object sender, MouseEventArgs e)
{
// Get current obj
var ellipse = e.Source as Ellipse;
if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
{
// Send obj to target
DragDrop.DoDragDrop(ellipse,ellipse,
DragDropEffects.Move);
}
}
private void UIElement_OnDrop(object sender, DragEventArgs e)
{
// Get obj
var obj = e.Data.GetData(e.Data.GetFormats()[0]) as UIElement;
// Get source and target Panel
var parent = (obj as FrameworkElement).Parent as Panel;
var sendertarget = sender as Panel;
if (obj != null && sendertarget != null && !sendertarget.Children.Contains(obj))
{
parent.Children.Remove(obj);
sendertarget.Children.Add(obj);
}
}
}
}
[/code]
Kết quả:


Source tại đây, chúc các bạn thành công!
Tuân Phạm
Chủ Nhật, 14 tháng 12, 2014
Ở bài trước chúng ta đã hiểu cơ bản về DataBinding - cơ chế liên kết dữ liệu giữa các thành phần Data và UI; chúng ta sẽ tiếp tục nói về DataBinding ở bài này với một đăc tính khác. Nói về WPF chúng ta sẽ phải sử dụng mô hình MVVM nếu muốn khai thác tối đa hiệu quả của công nghệ này mang lại nhưng chúng ta sẽ hiểu về MVVM ở một bài khác, sở dĩ tôi nói về điều này vì trong bài viết này chúng ta sẽ có một vài thuật ngữ liên quan(ViewModel).
Hiểu nôm na MVVM là mô hình tương tác giữa UI và phần logic, phần logic là một dạng dữ liệu được cung cấp cho thuộc tính DataContent cho mỗi Control và việc chúng ta sẽ làm là binding dữ liệu từ UI vào DataContent(hay gọi là ViewModel trong MVVM)
[code language="csharp"]btnSave.DataContent = new ViewModel();[/code]
Dưới đây là một đoạn XAML thể hiện việc UI sẽ binding dữ liệu để lấy thuộc tính NAME từ ViewModel, dữ liệu sẽ được cập nhật hai chiều và tiến hành cập nhập khi nào thì thuộc tính UpdateSourceTrigger sẽ quy định; ngoài ra StringFormat cũng là một thuộc tính cần lưu ý nhưng khá đơn giản - nó giống StringFomart ta vẫn hay dùng trong C#.
[code language="xml"]
<TextBox Text="{Binding Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,StringFormat='Name: {0}'}" Margin="0,5,0,0"></TextBox>
[/code]
UpdateSourceTrigger có bốn giá trị như sau: PropertyChanged,LostFocus,Explicit,Default
| PropertyChanged | Cập nhật khi có sự thay đổi value, đối với TextBox thì mỗi kí tự bạn nhập là một lần update vào Source, chúng ta sẽ tập trung vào phần này |
| LostFocus | Chỉ cập nhật khi Control đó bị mất Focus |
| Explicit | Chỉ cập nhật khi gọi binding.UpdateSource(); thường sẽ xử lý với các sự liện khác |
| Default | Dĩ nhiên nó là default và tương tự PropertyChanged |
INotifyPropertyChanged là một Interface mà một lớp ViewModel sẽ phải implement, interface này có duy nhất một thành viên sau
[code language="csharp"]public event PropertyChangedEventHandler PropertyChanged;[/code]
Đây là một event sẽ được gọi khi cần để báo rằng giá trị của một thuộc tính mà ViewModel chứa bị thay đổi. Chúng ta tận dụng điều này để làm gì, vâng! để thông báo cho UI rằng tôi đã bị thay đổi giá trị, hãy cập nhật giá trị ấy cho bạn đi.
Chúng ta sẽ làm một ví dự minh họa như sau: Tôi tạo một lớp ViewModel cho cho một đối tượng UI đại diện cho một con người (một Grid chứa các TextBox thể hiện thông tin một người):
code XAML
[code language="xml"]
<StackPanel x:Name="stpPer" Margin="30" VerticalAlignment="Top">
<TextBox Text="{Binding Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,StringFormat='Name: {0}'}" Margin="0,5,0,0"></TextBox>
<TextBox Text="{Binding Height,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,StringFormat='Height: {0}'}" Margin="0,5,0,0"></TextBox>
<TextBox Text="{Binding Width,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,StringFormat='Width: {0}'}" Margin="0,5,0,0"></TextBox>
</StackPanel>
[/code]
Tạo ViewModel
Ở đây tôi sẽ tạo một lớp abstract là ViewModelBase kế thừa interface INotifyPropertyChanged và implement thành viên của nó. Tôi tạo phương thức NotifyPropertyChanged("propertyName") để xử lý việc thay đổi value của Property(với propertyName là tên của Property bị Changed value.
[code language="csharp"]
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
[/code]
Tiếp sau tôi tạo lớp Persion kế thừa từ ViewModelBase với các thuộc tính Name,Height,Width để binding. Khi các thuộc tính nàu thay đổi value tôi sẽ gọi phương thức NotifyPropertyChanged("propertyName") để thông báo rằng propertyName này đã bị thay đổi giá trị và UI sẽ nhận được thông báo này nếu nó có đăng ký UpdateSourceTrigger=PropertyChanged.
[code language="csharp"]
public class Persion : ViewModelBase
{
public string Name
{
set
{
_name = value;
NotifyPropertyChanged("Name");
}
get { return _name; }
}
public string Height
{
set
{
_hieght = value;
NotifyPropertyChanged("Height");
}
get { return _hieght; }
}
public string Width
{
set
{
_width = value;
NotifyPropertyChanged("Widght");
}
get { return _width; }
}
private string _name;
private string _hieght;
private string _width;
}
[/code]
Code behind
[code language="csharp"]
public MainWindow()
{
InitializeComponent();
stpPer.DataContext = new Persion(){Height = "1m7",Name = "TuanPham",Width = "100,70,90"};
}
[/code]
Tôi lại thêm vào giao diện một TextBox và hai Button với mục đính thay đổi giá trị Name trong ViewModel xem trên UI có đổi không vaf show giá trị trong ViewModel khi changed giá trị trên TextBox name
[code language="xml"]
<Grid Margin="30">
<StackPanel x:Name="stpPer" VerticalAlignment="Top">
<TextBox Text="{Binding Name, Mode=TwoWay, StringFormat=Name: \{0\}, UpdateSourceTrigger=Default}" Margin="0,5,0,0"/>
<TextBox Text="{Binding Height, Mode=TwoWay, StringFormat=Height: \{0\}, UpdateSourceTrigger=PropertyChanged}" Margin="0,5,0,0"/>
<TextBox Text="{Binding Width, Mode=TwoWay, StringFormat=Width: \{0\}, UpdateSourceTrigger=PropertyChanged}" Margin="0,5,0,0"/>
</StackPanel>
<StackPanel Margin="0,0,0,20" Orientation="Vertical" VerticalAlignment="Bottom" HorizontalAlignment="Center">
<TextBox x:Name="txtChange" Height="23" TextWrapping="Wrap" Text="Please give me your name"/>
<Button x:Name="btnChange" Content="Change" HorizontalAlignment="Center"
Click="BtnChange_OnClick"
VerticalAlignment="Bottom" Width="75" Margin="0,10,0,0"/>
<Button x:Name="btnShow" Content="Show" HorizontalAlignment="Center"
Click="BtnShow_OnClick"
VerticalAlignment="Bottom" Width="75" Margin="0,10,0,0"/>
</StackPanel>
</Grid>
[/code]
Code behind
[code language="csharp"]
public MainWindow()
{
InitializeComponent();
stpPer.DataContext = new Persion(){Height = "1m7",Name = "TuanPham",Width = "100,70,90"};
}
private void BtnChange_OnClick(object sender, RoutedEventArgs e)
{
(stpPer.DataContext as Persion).Name = txtChange.Text;
}
private void BtnShow_OnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show((stpPer.DataContext as Persion).Name);
}
[/code]
Kết quả:

Chúc các bạn thành công: download source
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 ...
