الخميس، 19 مايو 2011

WPF Data Binding


Introduction
In WPF, the term data is generally used to describe an arbitrary .NET object. You can see this naming pattern in terms like data binding, data templates, and data triggers.
 A piece of data could be a collection object, an XML file, a web service, a database table, a custom object, or even a WPF element such as a Button.
Therefore, data binding is about tying together arbitrary .NET objects. The classic scenario is providing a visual representation (for example, in a ListBox or ListView) of items in an XML file, database, or an in-memory collection.
For example, instead of iterating through a data source and manually adding a ListBoxItem to a ListBox for each one, it would be nice to just say, “Hey, ListBox! Get your items from over here. And keep them up to date, please. Oh yeah, and format them to look like this.” Data binding enables this and much more.

Introducing the Binding Object
The key to data binding is a System.Windows.Data.Binding object that "glues"  two properties together and keeps a channel of communication open between them. You can set up a Binding once, and then have it do all the synchronization work for the remainder of the application’s lifetime.

Binding Basics
Binding is simply keeping two data points in sync with each other. Data point is an abstract concept, the idea of a single “node” of data. A data point can be described in a variety of ways; generally it is a data source and query. For example, a property data point would be an object and a property name. The property name determines the property on the source object from which data should be retrieved.
XAMl
  <StackPanel Height="119" Name="stackPanel1" Width="434">
        <TextBox Height="23" Name="textBox1" Width="270" TextChanged="textBox1_TextChanged" />
        <ContentControl Height="32" Name="contentControl1" Width="337" />
    StackPanel>

In WPF the Binding class represents a data point. To construct a binding, we provide it a source (the data source) and path (the query). In this case we can create a data point that references the Text property of a TextBox object:

        private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
        {
            Binding bind = new Binding();
            bind.Source = textBox1;
            bind.Path = new PropertyPath("Text");

            contentControl1.SetBinding(ContentControl.ContentProperty, bind);
        }


Or you can write your code in XAML

Source
  <StackPanel Height="119" Name="stackPanel1" Width="434">
        <TextBox Height="23" Name="textBox1" Width="270" TextChanged="textBox1_TextChanged" />
        <ContentControl Height="32" Name="contentControl1" Width="337"  Content='{Binding ElementName=textBox1,Path=Text}' />
    StackPanel>               


Example #2



The ListBox that has six ListBoxItems declared. The second TextBlock in the code example has a property called Text (specified in XAML property-element syntax with the XML child element ), which will contain the text for the TextBlock. The Text property declares a binding to the ListBox's selected item with the tag. The ElementName attribute of the Binding tag indicates the name of the control that the TextBlock's Text property is bound to. The Path attribute indicates the property of the element (in this case the ListBox) that we will be binding to. The result of this code is that when a color is selected from the ListBox, the name of that color is shown in the TextBlock.
<StackPanel>
        <TextBlock Width="248" Height="24" Text="Colors:"
        TextWrapping="Wrap"/>
        <ListBox x:Name="lbColor" Width="248" Height="56">
            <ListBoxItem Content="Blue"/>
            <ListBoxItem Content="Green"/>
            <ListBoxItem Content="Yellow"/>
            <ListBoxItem Content="Red"/>
            <ListBoxItem Content="Purple"/>
            <ListBoxItem Content="Orange"/>
        ListBox>
        <TextBlock Width="248" Height="24" Text="You selected color:" />
        <TextBlock Width="248" Height="24">
        <TextBlock.Text>
            <Binding ElementName="lbColor" Path="SelectedItem.Content"/>
        TextBlock.Text>
        TextBlock>
    StackPanel>

Example # 3 (Binding FontFamily / FontSize value for current Control)


   <StackPanel TextBlock.FontSize="20" >

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <TextBlock Text="This TextBlock has a FontFamily of " />
            <TextBlock Text="{Binding RelativeSource={RelativeSource self},Path=FontFamily}" />
            <TextBlock Text=" and a FontSize of " />
            <TextBlock Text="{Binding RelativeSource={RelativeSource self},Path=FontSize}" />
        StackPanel>

Binding Windows ItSelf


<Window x:Class="WpfApplication20.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Name="window">

        <StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>WindowState:Label>
                <Label Content="{Binding ElementName=window,Path=WindowState}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>MinWidth:Label>
                <Label Content="{Binding ElementName=window,Path=MinWidth}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>MinHeight:Label>
                <Label Content="{Binding ElementName=window,Path=MinHeight}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>SizeToContent:Label>
                <Label Content="{Binding ElementName=window,Path=SizeToContent}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>MaxWidth:Label>
                <Label Content="{Binding ElementName=window,Path=MaxWidth}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>MaxHeight:Label>
                <Label Content="{Binding ElementName=window,Path=MaxHeight}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>Width:Label>
                <Label Content="{Binding ElementName=window,Path=Width}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>Height:Label>
                <Label Content="{Binding ElementName=window,Path=Height}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>Actual Width:Label>
                <Label Content="{Binding ElementName=window,Path=ActualWidth}"/>
            StackPanel>
            <StackPanel Orientation="Horizontal">
                <Label>Actual Height:Label>
                <Label Content="{Binding ElementName=window,Path=ActualHeight}"/>
            StackPanel>
        StackPanel>
    Window>


Binding from Object



  <StackPanel>
        <TextBox x:Name="firstNameTextBox" Width="200" Margin="0,4" />

        <TextBox x:Name="lastNameTextBox" Width="200" Margin="0,4" />

        <TextBlock x:Name="fullNameTextBlock" Background="LightBlue" Margin="0,4" />
       
    StackPanel>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication20
{
  
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            ManuallyMoveData();
        }

        private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
        {
           // contentControl1.Content = textBox1.Text;
        }

        Person _person;

        // This method is invoked by the Window's constructor.
        private void ManuallyMoveData()
        {
            _person = new Person
            {
                FirstName = "Ahmed",
                LastName = "EL Bohoty"
            };

            this.firstNameTextBox.Text = _person.FirstName;
            this.lastNameTextBox.Text = _person.LastName;
            this.fullNameTextBlock.Text = _person.FullName;

            this.firstNameTextBox.TextChanged += firstNameTextBox_TextChanged;
            this.lastNameTextBox.TextChanged += lastNameTextBox_TextChanged;
        }

        void lastNameTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            _person.LastName = this.lastNameTextBox.Text;
            this.fullNameTextBlock.Text = _person.FullName;
        }

        void firstNameTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            _person.FirstName = this.firstNameTextBox.Text;
            this.fullNameTextBlock.Text = _person.FullName;
        }
    }

    public class Person
    {
        public string FirstName { getset; }
        public string LastName { getset; }

        public string FullName
        {
            get
            {
                return String.Format("{0}, {1}",
                    this.LastName, this.FirstName);
            }
        }
    }
}


Binding to XML


Steps
1- Make xml file and add it to your solution
xml version="1.0" encoding="utf-8" ?>
<Teams xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <Team>
    <Id>1Id>
    <Name>Ahmed rabieName>
    <Conference>NFC WestConference>
  Team>

  <Team>
    <Id>2Id>
    <Name>Mohamed RabieName>
    <Conference>NFC SouthConference>
  Team>

  <Team>
    <Id>3Id>
    <Name>Malek Ahmed RabieName>
    <Conference>AFC NorthConference>
  Team>

  <Team>
    <Id>4Id>
    <Name>Abd-Allah Maher AnisName>
    <Conference>AFC EastConference>
  Team>

Teams>






2-Design
   <Window.Resources>
               
        
        <Style x:Key="labelStyle" TargetType="{x:Type Label}">
            <Setter Property="VerticalAlignment" Value="Top" />
            <Setter Property="HorizontalAlignment" Value="Right" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="MinWidth" Value="80" />
        Style>

        <Style x:Key="textboxStyle" TargetType="{x:Type TextBox}">
            <Setter Property="Width" Value="200">Setter>
            <Setter Property="Margin" Value="0,0,0,0" />
        Style>
       
        <Style x:Key="fieldsetStyle" TargetType="{x:Type StackPanel}">
            <Setter Property="Margin" Value="0,3,0,3" />           
        Style>

        <DataTemplate x:Key="teamItemTemplate">
            <Label Content="{Binding XPath=Name}"/>
        DataTemplate>
       
    Window.Resources>
       
    <Grid Margin="0,10,0,0">       
       
        <Grid.DataContext>
            <XmlDataProvider x:Name="TeamData" Source="Teams.xml" XPath="Teams/Team" />
        Grid.DataContext>
      
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        Grid.RowDefinitions>
       
        <DockPanel Grid.Column="0" Margin="5,0,0,0">
            <Border Height="30" Padding="0" Background="#4E87D4" DockPanel.Dock="Top">
                <Label VerticalAlignment="Center" Foreground="White">TeamsLabel>
            Border>

            <ListBox x:Name="TeamsListBox" Margin="0,0,0,20" DockPanel.Dock="Left"
                     ItemsSource="{Binding}"
                     ItemTemplate="{StaticResource teamItemTemplate}"
                     IsSynchronizedWithCurrentItem="True"
                     Visibility="Visible" SelectionMode="Single">
            ListBox>
        DockPanel>
       
        <StackPanel Grid.Column="1" Margin="0,0,5,0">
          
            <StackPanel Orientation="Horizontal">
                <Label Style="{StaticResource labelStyle}">ID:Label>
                <TextBox Style="{StaticResource textboxStyle}" Text="{Binding XPath=Id}" />
            StackPanel>
            <StackPanel Orientation="Horizontal" Style="{StaticResource fieldsetStyle}">
                <Label Style="{StaticResource labelStyle}">Team:Label>
                <TextBox Style="{StaticResource textboxStyle}" Text="{Binding XPath=Name}" />
            StackPanel>
            <StackPanel Orientation="Horizontal" Style="{StaticResource fieldsetStyle}">
                <Label Style="{StaticResource labelStyle}">Conference:Label>
                <TextBox Style="{StaticResource textboxStyle}" Text="{Binding XPath=Conference}" />
            StackPanel>
           
        StackPanel>    
       
        <DockPanel Grid.Column="1">
            <Button x:Name="SaveTeamsButton" DockPanel.Dock="Bottom" Click="SaveTeamsButton_Click" Height="20" Width="50">SaveButton>
        DockPanel>
       
    Grid>

3- Coding
  public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
            TeamData.Source = new Uri(appPath + @"\Teams.xml");
        }
        private void SaveTeamsButton_Click(object sender, RoutedEventArgs e)
        {
            string source = TeamData.Source.LocalPath;
            TeamData.Document.Save(source);
        }

    }
Customize Data Display with Data Binding and WPF
§  Suppose you have a simple class called FullName, which stores a person's name. You want to display a list of names and have each person's last name appear more prominently than the other parts of the name. To do this you could create a DataTemplate that describes how to render a FullName object.
§  There is an ItemsControl in the window's XAML file. It creates a simple list of items that the user cannot select or remove. The ItemsControl has a DataTemplate assigned to its ItemTemplate property, with which it renders each FullName instance created in the window's constructor. You should notice how most of the TextBlock elements in the DataTemplate have their Text property bound to properties on the FullName object that they represent.
    
        <ItemsControl ItemsSource="{Binding Path=.}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
              <TextBlock FontWeight="Bold" Text="{Binding LastName}" />
              <TextBlock Text=", " />
              <TextBlock Text="{Binding FirstName}" />
              <TextBlock Text=" " />
              <TextBlock Text="{Binding MiddleInitial}" />
                    StackPanel>
                DataTemplate>
            ItemsControl.ItemTemplate>
        ItemsControl>

By using a DataTemplate to render the name, it is easy to accentuate each person's last name because the corresponding TextBlock's FontWeight is bold. This simple example demonstrates the fundamental relationship between WPF data binding and templates
Code
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            base.DataContext = new FullName[]
        {
            new FullName
            {
                FirstName = "Ahmed",
                MiddleInitial = 'R',
                LastName = "Rabie"
            },
            new FullName
            {
                FirstName = "Ola",
                MiddleInitial = 'R',
                LastName = "Maher"
            },
            new FullName
            {
                FirstName = "Mohamed",
                MiddleInitial = 'M',
                LastName = "Anis"
            }
        };
        }
    }

0 التعليقات: