Data Binding In WPF
2006-04-06 00:33
399 查看
Data binding is a very important feature in every development platform, for all of you who have been using the data binding mechanism of ASP.NET, you must think that data binding in ASP.NET is quite flexible, and extensible, you can declaratively bind the data to any property for any web control, when the data is changed through user interactituon with the interface, the underlying data store will be changed accordingly. fortunately WPF comes up with another quite similar data binding mechanism which can make data access super easy for developers. For demonstration purpose I plan to write a slide show application which will take advantage of data binding capability in WPF, with this application, you can select a set of images through a dialog, and the application will recursively display those images one at a time, so the slide show effects can be achieved.
First of all, I need to write a helper class which will perform the actual slide show operations behind the scene:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace SlideShow
{
public class SlideShowManager: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private String[] imageFiles;
private Int32 interval = 2;
private Int32 currentIndex = 0;
private DispatcherTimer timer;
private Image targetImage;
public SlideShowManager(String[] imageFiles)
{
this.imageFiles = imageFiles;
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, interval);
timer.Tick += TimerOnTick;
timer.Start();
}
public Image TargetImage
{
get { return targetImage; }
set { targetImage = value; }
}
public BitmapImage Current
{
get
{
currentIndex = (currentIndex + 1) % imageFiles.Length;
return new BitmapImage(new Uri(imageFiles[currentIndex], UriKind.Absolute));
}
}
public Int32 Interval
{
get { return interval; }
set
{
if (value > 0)
{
timer.Stop();
timer.Interval = new TimeSpan(0, 0, value);
timer.Start();
}
}
}
private void FadeIn()
{
DoubleAnimation fadeInAnimation = new DoubleAnimation(0.1, 1, TimeSpan.FromSeconds(Interval));
targetImage.BeginAnimation(Image.OpacityProperty, fadeInAnimation);
}
private void TimerOnTick(Object sender, EventArgs e)
{
if (imageFiles != null && imageFiles.Length > 1)
{
FadeIn();
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Current"));
}
}
}
}
Note that this class implements the INotifyPropertyChanged event, for any object which wants to act as data source object, it should implement this interface, basically this interface provides a notifcation mechanism in the data binding scenario, when any property of this class is changed, it will send a notification to the data binding UI elements, so the UI elements can see the change and refresh its visual display accordingly.
Now I have the house keeping class at hand, what I need then is a UI which hosts an Image element, whose Source property is bound to the SlideShowManager's Current property:
<Window x:Class="SlideShow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SlideShow" Height="300" Width="300"
>
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open" Executed="OpenCommandExecutedHandler" />
<CommandBinding Command="ApplicationCommands.Close" Executed="CloseCommandExecutedHandler" />
</Window.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Open" Name="menuOpen" Command="ApplicationCommands.Open" />
<MenuItem Header="E_xit" Name="menuExit" Command="ApplicationCommands.Close"/>
</MenuItem>
</Menu>
<Image x:Name="slideshowImage" Opacity="1"/>
</DockPanel>
</Window>
In the code beside file for this XAML file, I write some lines of code like this:
using System;
using System.Windows.Input;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SlideShow
{
public partial class MainWindow : Window
{
private SlideShowManager manager;
public MainWindow()
{
InitializeComponent();
}
private void OpenSlideShow()
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = dlg.Filter = "PNG file(*.png)|*.png|BMP file(*.bmp)|*.bmp|JPEG file(*.jpg)|*.jpg|GIF file(*.gif)|*.gif|Image Files(*.*) | *.*";
dlg.FilterIndex = 3;
dlg.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
dlg.Multiselect = true;
if (dlg.ShowDialog() == true)
{
manager = new SlideShowManager(dlg.FileNames);
manager.Interval = 2;
manager.TargetImage = slideshowImage;
Binding binding = new Binding("Current");
using (binding.DeferChanges())
{
binding.Mode = BindingMode.OneWay;
binding.Source = manager;
}
BindingOperations.SetBinding(slideshowImage, Image.SourceProperty, binding);
}
}
private void OpenCommandExecutedHandler(Object sender, ExecutedRoutedEventArgs e)
{
OpenSlideShow(); Binding binding = new Binding("Current");
using (binding.DeferChanges())
{
binding.Mode = BindingMode.OneWay;
binding.Source = manager;
}
BindingOperations.SetBinding(slideshowImage, Image.SourceProperty, binding);
}
private void CloseCommandExecutedHandler(Object sender, ExecutedRoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
}
You can see from this code that in the OpenSlideShow() method, I open up a OpenFileDialog control so user can select a set of images he or she want to show up, and then I create the data binding code like following:
Binding binding = new Binding("Current");
using (binding.DeferChanges())
{
binding.Mode = BindingMode.OneWay;
binding.Source = manager;
}
BindingOperations.SetBinding(slideshowImage, Image.SourceProperty, binding); This is the actual data binding operation I want to talk about, so you must be surprised by how easy data binding can be achieved in WPF. in fact, you also can declaratively perform the data binding operation in XAML, for example:
<Window x:Class="RssReader.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="RssReader" Height="444" Width="619">
<Window.Resources>
<XmlDataProvider x:Key="RssData" Source="http://sheva.cnblogs.com/Rss.aspx" IsAsynchronous="True"/>
</Window.Resources>
<DockPanel>
<Label DockPanel.Dock="Top" FontSize="14" FontWeight="Bold"
Content="{Binding Source={StaticResource RssData}, XPath=/rss/channel/title}"/>
<Label DockPanel.Dock="Top"
Content="{Binding Source={StaticResource RssData}, XPath=/rss/channel/description}" />
<DockPanel DockPanel.Dock="Top"
DataContext="{Binding Source={StaticResource RssData}, XPath=/rss/channel/item}">
<ScrollViewer DockPanel.Dock="Left" >
<ListBox ItemsSource="{Binding}"
Width="200"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=title}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
<Frame Source="{Binding XPath=link}" Width="Auto"/>
</DockPanel>
</DockPanel>
</Window>
This markup can build a very simple RSS reader application, quite stunning is isn't?
First of all, I need to write a helper class which will perform the actual slide show operations behind the scene:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace SlideShow
{
public class SlideShowManager: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private String[] imageFiles;
private Int32 interval = 2;
private Int32 currentIndex = 0;
private DispatcherTimer timer;
private Image targetImage;
public SlideShowManager(String[] imageFiles)
{
this.imageFiles = imageFiles;
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, interval);
timer.Tick += TimerOnTick;
timer.Start();
}
public Image TargetImage
{
get { return targetImage; }
set { targetImage = value; }
}
public BitmapImage Current
{
get
{
currentIndex = (currentIndex + 1) % imageFiles.Length;
return new BitmapImage(new Uri(imageFiles[currentIndex], UriKind.Absolute));
}
}
public Int32 Interval
{
get { return interval; }
set
{
if (value > 0)
{
timer.Stop();
timer.Interval = new TimeSpan(0, 0, value);
timer.Start();
}
}
}
private void FadeIn()
{
DoubleAnimation fadeInAnimation = new DoubleAnimation(0.1, 1, TimeSpan.FromSeconds(Interval));
targetImage.BeginAnimation(Image.OpacityProperty, fadeInAnimation);
}
private void TimerOnTick(Object sender, EventArgs e)
{
if (imageFiles != null && imageFiles.Length > 1)
{
FadeIn();
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Current"));
}
}
}
}
Note that this class implements the INotifyPropertyChanged event, for any object which wants to act as data source object, it should implement this interface, basically this interface provides a notifcation mechanism in the data binding scenario, when any property of this class is changed, it will send a notification to the data binding UI elements, so the UI elements can see the change and refresh its visual display accordingly.
Now I have the house keeping class at hand, what I need then is a UI which hosts an Image element, whose Source property is bound to the SlideShowManager's Current property:
<Window x:Class="SlideShow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SlideShow" Height="300" Width="300"
>
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open" Executed="OpenCommandExecutedHandler" />
<CommandBinding Command="ApplicationCommands.Close" Executed="CloseCommandExecutedHandler" />
</Window.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Open" Name="menuOpen" Command="ApplicationCommands.Open" />
<MenuItem Header="E_xit" Name="menuExit" Command="ApplicationCommands.Close"/>
</MenuItem>
</Menu>
<Image x:Name="slideshowImage" Opacity="1"/>
</DockPanel>
</Window>
In the code beside file for this XAML file, I write some lines of code like this:
using System;
using System.Windows.Input;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SlideShow
{
public partial class MainWindow : Window
{
private SlideShowManager manager;
public MainWindow()
{
InitializeComponent();
}
private void OpenSlideShow()
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = dlg.Filter = "PNG file(*.png)|*.png|BMP file(*.bmp)|*.bmp|JPEG file(*.jpg)|*.jpg|GIF file(*.gif)|*.gif|Image Files(*.*) | *.*";
dlg.FilterIndex = 3;
dlg.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
dlg.Multiselect = true;
if (dlg.ShowDialog() == true)
{
manager = new SlideShowManager(dlg.FileNames);
manager.Interval = 2;
manager.TargetImage = slideshowImage;
Binding binding = new Binding("Current");
using (binding.DeferChanges())
{
binding.Mode = BindingMode.OneWay;
binding.Source = manager;
}
BindingOperations.SetBinding(slideshowImage, Image.SourceProperty, binding);
}
}
private void OpenCommandExecutedHandler(Object sender, ExecutedRoutedEventArgs e)
{
OpenSlideShow(); Binding binding = new Binding("Current");
using (binding.DeferChanges())
{
binding.Mode = BindingMode.OneWay;
binding.Source = manager;
}
BindingOperations.SetBinding(slideshowImage, Image.SourceProperty, binding);
}
private void CloseCommandExecutedHandler(Object sender, ExecutedRoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
}
You can see from this code that in the OpenSlideShow() method, I open up a OpenFileDialog control so user can select a set of images he or she want to show up, and then I create the data binding code like following:
Binding binding = new Binding("Current");
using (binding.DeferChanges())
{
binding.Mode = BindingMode.OneWay;
binding.Source = manager;
}
BindingOperations.SetBinding(slideshowImage, Image.SourceProperty, binding); This is the actual data binding operation I want to talk about, so you must be surprised by how easy data binding can be achieved in WPF. in fact, you also can declaratively perform the data binding operation in XAML, for example:
<Window x:Class="RssReader.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="RssReader" Height="444" Width="619">
<Window.Resources>
<XmlDataProvider x:Key="RssData" Source="http://sheva.cnblogs.com/Rss.aspx" IsAsynchronous="True"/>
</Window.Resources>
<DockPanel>
<Label DockPanel.Dock="Top" FontSize="14" FontWeight="Bold"
Content="{Binding Source={StaticResource RssData}, XPath=/rss/channel/title}"/>
<Label DockPanel.Dock="Top"
Content="{Binding Source={StaticResource RssData}, XPath=/rss/channel/description}" />
<DockPanel DockPanel.Dock="Top"
DataContext="{Binding Source={StaticResource RssData}, XPath=/rss/channel/item}">
<ScrollViewer DockPanel.Dock="Left" >
<ListBox ItemsSource="{Binding}"
Width="200"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=title}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
<Frame Source="{Binding XPath=link}" Width="Auto"/>
</DockPanel>
</DockPanel>
</Window>
This markup can build a very simple RSS reader application, quite stunning is isn't?
相关文章推荐
- Databinding in WPF
- Debug Databinding Issues in WPF
- Data Binding in WPF
- csharp: Data binding in WPF DataGrid control
- Debug Databinding Issues in WPF
- Data Binding in WPF
- csharp: Data binding in WPF DataGrid control
- Debugging Data Binding in WPF
- csharp: Data binding in WPF DataGrid control
- How can I create a data binding in code using WPF?
- WPF数据绑定(2 绑定列表数据Binding to List Data)
- UpdateSourceTrigger Property in WPF Binding
- WPF Tips: Data Binding Converter一例:bool与Visibility之间的转换
- WPF DataBinding
- WPF data-binding
- DataBinding In Kotlin编译不通过
- WPF databinding trick (part 2)
- Binding and styling text to a RichTextBox in WPF
- #448 – 在Grid中显示数据绑定元素的集合(Data Binding Elements in a Collection to a Grid)
- Enum Binding ItemsSource In WPF