您的位置:首页 > 其它

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?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: