Привязка

Последнее обновление: 1.11.2015

Привязка подразумевает взаимодействие двух объектов: источника и приемника. Объект-приемник создает привязку к определенному свойству объекта-источника. В случае модификации объекта-источника, объект-приемник также будет модифицирован. Например,

<StackPanel>
        <TextBlock Text="{Binding ElementName=textBox1,Path=Text}" 
                       Foreground="White" Height="30" />
         <TextBox x:Name="textBox1" />
</StackPanel>

В данном случае при осуществлении ввода текста в элемент TextBox, он сразу же будет отображаться в элементе TextBlock и в другом элементе TextBox. После изменения текста во втором элементе TextBox, текст также будет меняться вдругих элементах. Конечно, в данном случае можно было бы прописать обработчик события Text_Changed, но в данном случае привязка выглядит намного изящнее.

Синтаксис привязки в общем случае выглядит следующим образом: в фигурных скобках сначала идет ключевое слово Binding, объявляя привязку, а затем свойства объекта Binding с соответствующими значениями:
Например, Элемент.Свойство="{Binding ElementName=Имя_объекта-источника, Path=Свойство_объекта-источника}"

Если попробовать создать вышеописанную привязку элемента TextBlock к элементу TextBox в файле кода, то код будет выглядеть так:

using System.Windows.Data;
...........................
Binding bind = new Binding();
bind.ElementName = "textBox1";
bind.Path = new PropertyPath("Text");
textBlock1.SetBinding(TextBlock.TextProperty, bind);

    Некоторые свойства класса Binding

  • ElementName - имя элемента, к которому создается привязка

  • Mode - направление привязки

  • Path - путь к данным объекта, может принимать сложные значения, например, SelectedItem.Header для TreeView

  • RelativeSource создает привязку относительно текущего объекта

  • Source указывает на объект-источник, если он не является элементом управления.

Mode может принимать следующие значения:

  • OneWay - свойство объекта-приемника изменяется после модификации свойства объекта-источника.

  • OneTime - свойство объекта-приемника устанавливается по свойству объекта-источника только один раз.

  • TwoWay- оба объекта могут изменять привязанные свойства друг друга.

Пример использования двухсторонней привязки:

<StackPanel>
            <TextBox x:Name="textBox1"  />
            <TextBox x:Name="textBox2" Text="{Binding ElementName=textBox1,Path=Text, Mode= TwoWay}" />
        </StackPanel>

Чтобы создать привязку относительно данного элемента используется свойство RelativeSource класса Binding. Например, можно создать привязку на этот же элемент:

<TextBlock Width="100" Height="30" Background="White" Text="{Binding RelativeSource={RelativeSource Mode=Self}, Path=FontFamily}" />

В результате элемент TextBlock будеть отображать название текущего шрифта

При создании относительной привязки свойству RelativeSource класса Binding используется одноименный объект RelativeSource. Этот объект устанавливает способ привязки (свойство Mode), например, Self. Другой способ привязки - FindAncestor - указывает на родительский элемент или на дерево родительских элементов, поскольку дерево может иметь много уровней вложения. При этом задается также свойство AncestorType, оно указывает на тип родительского элемента. Дополнительно может указываться свойство AncestorLevel - оно указывает на вхождение родительского элемента в дерево (по умолчанию равно единице):

 <Grid x:Name="LayoutRoot" Background="Black">
            <TextBlock Foreground="White" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}, Path=Name}" />
    </Grid>

В данном случае ведется поиск родительского элемента типа Grid, а затем отображается значение его свойства Name.

Если до этого мы создавали привязку к элементам, то сейчас попробуем сделать привязку к объекту, не являющемуcя элементом управления. Определим класс Team:

   public class Team
    {
        public string country{ get; set; }
        public int place { get; set; }
        public int score { get; set; }
		public Team(string _country, int _place, int _score)
        {
            this.country = _country;
            this.place = _place;
            this.score = _score;
        }
        public Team()
        { }
    }

Теперь создадим объект этого класса и определим к нему привязку:

<UserControl x:Class="TestApplication.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:TestApplication"
    mc:Ignorable="d"
    d:DesignHeight="200" d:DesignWidth="250">
    <UserControl.Resources>
        <local:Team x:Key="Russia" country="Russia" place="1" score="23" />
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="Black">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Страна:" Foreground="White"/>
            <TextBlock x:Name="textBlock1" Text="{Binding Source={StaticResource Russia},Path=country}"
                        Foreground="White" Margin="60 0" />
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 20">
            <TextBlock Text="Набранные очки:" Foreground="White"/>
            <TextBlock x:Name="textBlock2" Text="{Binding Source={StaticResource Russia},Path=score}"
                        Foreground="White" Margin="10 0" />
        </StackPanel>
    </Grid>
</UserControl>

Обновление элемента после обновления привязанного объекта

В последнем случае есть одна небольшая неприятность: в случае изменения свойства привязка автоматически не обновит текст в элементе TextBlock. Чтобы выйти из этой ситуации, придется написать несколько строк кода.

Добавим к предыдущему примеру объект StackPanel с элементом TextBox, куда будет вводится новое значение, и кнопку, которая будет генерировать обновление.

<StackPanel Orientation="Horizontal" Margin="0 60" VerticalAlignment="Center">
            <TextBox Name="textbox1" Width="150" Text="Ввведите кол-во очков"></TextBox>
            <Button Content="Обновить" Foreground="White" Background="Black" Margin="15 0 0 0" Click="Button_Click" />        
  </StackPanel>

Теперь нам надо реализовать в классе Team интерфейс INotifyPropertyChanged. С помощью события PropertyChanged он уведомляет инфраструктуру Silverlight об изменении свойств объекта. Для этого подкорректируем немного класс Team:

public class Team : INotifyPropertyChanged //using System.ComponentModel
    {
        private string _country;
        private int _place;
        private int _score;
        public string country
        { 
            get
            {
                return _country;
            }
            set
            {
                _country = value;
                OnPropertyChanged(new PropertyChangedEventArgs("country"));
            }
        }
        public int place 
        {
            get
            {
                return _place;
            }
            set
            {
                _place = value;
                OnPropertyChanged(new PropertyChangedEventArgs("place"));
            }
        }
        public int score 
        {
            get
            {
                return _score;
            }
            set
            {
                _score = value;
                OnPropertyChanged(new PropertyChangedEventArgs("score"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e)
        {
        if (PropertyChanged!=null) 
            PropertyChanged(this, e);
        }
		public Team(string _country, int _place, int _score)
        {
            this.country = _country;
            this.place = _place;
            this.score = _score;
        }
        public Team()
        { }
    }
   

Тогда код Button1_Click можно свести к простому изменению свойства, и после нажатия кнопки связанный элемент TextBlock автоматически изменит свой текст

	private void Button_Click(object sender, RoutedEventArgs e)
        {
            int res;
            ((Team)this.Resources["Russia"]).score = Int32.TryParse(textbox1.Text,out res)?res: 0;
        }
   

Использование контекста данных (DataContext) и привязка к данным

У объекта FrameworkElement, от которого наследуются элементы управления, есть интересное свойство DataContext. Оно позволяет задавать для элемента и вложенных в него элементов некоторый контекст данных. Тогда вложенные элементы могут использовать объект Binding для привязки к этому контексту. Например, используем ранее определенный класс Team и создадим контекст данных из объекта этого класса:

 <UserControl x:Class="TestApplication.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:TestApplication"
    mc:Ignorable="d"
    d:DesignHeight="200" d:DesignWidth="250">
    <UserControl.Resources>
        <local:Team x:Key="comand" country="Бразилия" place="1" score="100" />
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" DataContext="{StaticResource comand}" ShowGridLines="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock Text="Место" Grid.Column="0" Grid.Row="0" Margin="10" />
        <TextBlock Text="{Binding place}" Grid.Column="0" Grid.Row="1" Margin="10" />
        <TextBlock Text="Страна" Grid.Column="1" Grid.Row="0" Margin="10"/>
        <TextBlock Text="{Binding country}" Grid.Column="1" Grid.Row="1" Margin="10" />
        <TextBlock Text="Очки" Grid.Column="2" Grid.Row="0" Margin="10" />
        <TextBlock Text="{Binding score}" Grid.Column="2" Grid.Row="1" Margin="10" />
    </Grid>
</UserControl>

Таким образом мы задаем свойству DataContext некоторый объект, например, ресурс. Затем осуществляем привязку к различным свойствам этого ресурса.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850