Опубликован: 05.08.2010 | Уровень: специалист | Доступ: платный
Лекция 1:

Основы привязки данных в WPF

Вкладка Page1. Обновление значений свойств элементов без использования привязки

Вначале построим пример передачи информации между элементами с использованием событий, как это традиционно делается в обычных приложениях

  • Поместите в разметку файла Window1.xaml следующий дескрипторный код с вкладкой Page1
<Window x:Class="ElementWithElement.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Привязка элемента к элементу" 
    MinHeight="300" 
    MinWidth="300"
    Height="300" 
    Width="300"
    WindowStartupLocation="CenterScreen"
    Background="{StaticResource ControlColorBrush}"
    Loaded="Window_Loaded">
    <Grid>
        <TabControl>
            <!-- Page1. Использование обработчика для обновления свойств -->
            <TabItem Header="Page1">
                <StackPanel>
                    <TextBlock FontSize="16" TextDecorations="Underline"
                        TextAlignment="Center" Margin="0,5,0,15">
                        <TextBlock.Foreground>
                            <SolidColorBrush Color="Red" />
                        </TextBlock.Foreground>
                        Соединение свойств без привязки
                    </TextBlock>
                    <StackPanel Orientation="Horizontal" Margin="5">
                        <Label Name="label1" Width="40" />
                        <Slider Name="slider1" Width="230" 
                            Maximum="54"
                            TickFrequency="2" TickPlacement="TopLeft"
                            ValueChanged="slider1_ValueChanged" />
                    </StackPanel>
                    <TextBlock Name="textBlock1" Margin="0,10" 
                        Foreground="Blue">
                        Simple Text
                    </TextBlock>
                </StackPanel>
            </TabItem>
        </TabControl>
    </Grid>
</Window>
  • Заполните файл процедурного кода Window1.xaml.cs следующим образом
using System;
using System.Collections.Generic;
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 ElementWithElement
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Инициализация для Page1
            int value = Convert.ToInt32(textBlock1.FontSize);// Явное приведение типов
            slider1.Minimum = value;    // Тип int приводится к double по умолчанию
            label1.Content = value.ToString();// Content имеет тип Object и проглотит все
        }
    
        // Обработчик для Page1
        private void slider1_ValueChanged(object sender, 
            RoutedPropertyChangedEventArgs<double> e)
        {
            if (!this.IsLoaded)
                return;// Событие возбуждается, а элементы еще не созданы
    
            Slider slider = (Slider)sender; // Повышаем полномочия ссылки
            int value = (int)slider.Value;  // Явное приведение типов
            label1.Content = value;         // Content имеет тип Object и проглотит все
            textBlock1.FontSize = value;    // Тип int приводится к double неявно
        }
    }
}
  • Запустите приложение и испытайте работу элементов вкладки Page1. Разберитесь с кодом разметки и процедурным кодом

Результат будет выглядеть так


Вкладка Page2. Однонаправленная привязка на основе разметки по синтаксису элементов свойств

Привязка на основе разметки более предпочтительна, потому что она проще и требует меньше работы. Хотя, создание привязки в коде тоже имеет место быть. В данном примере мы решим ту же самую задачу, что и в предыдущем примере. Только будем использовать уже привязку свойства-источника Value бегунка к элементам отображения Label и TextBlock.

  • Добавьте в контейнер TabControl после элемента вкладки Page1 файла Window1.xaml еще один элемент вкладки с именем Page2 со следующим кодом привязки по синтаксису элементов свойств
<!-- Page2. Использование привязки по синтаксису элементов свойств -->
            <TabItem Header="Page2">
                <StackPanel>
                    <TextBlock FontSize="16" TextDecorations="Underline"
                        TextAlignment="Center" Margin="0,5,0,15">
                        <TextBlock.Foreground>
                            <SolidColorBrush Color="Red" />
                        </TextBlock.Foreground>
                        Использование привязки по
                        <LineBreak />
                        синтаксису элементов свойств
                    </TextBlock>
                    <StackPanel Orientation="Horizontal" Margin="5">
                        <Label Width="40" ContentStringFormat="F0">
                            <Label.Content>
                                <Binding ElementName="slider2" Path="Value" Mode="OneWay" />
                            </Label.Content>
                        </Label>
                        <Slider Name="slider2" Width="230" 
                            Minimum="11" Maximum="54"
                            TickFrequency="2" TickPlacement="Both" />
                    </StackPanel>
                    <TextBlock Margin="0,10" Foreground="Blue">
                        <TextBlock.FontSize>
                            <Binding ElementName="slider2" Path="Value" Mode="OneWay" />
                        </TextBlock.FontSize>
                        Simple Text
                    </TextBlock>
                </StackPanel>
            </TabItem>

В разметке вкладки Page2 мы оставили имя только источника, поскольку на него ссылаемся в привязке. А имена приемников нам просто не нужны, так как обработчики в процедурном коде мы не создаем. Соответственно, убрана регистрация обработчика для события Slider.ValueChanged, в результате чего код получился намного проще, чем в примере вкладки Page2. Добавлен параметр Minimum="11", определяющий нижнее значение ползунка. Обратите внимание, что при инициализации вкладки это значение сразу отображается элементами Label и TextBlock - механизм привязки знает свое дело.

  • Попробуйте установить другое значение Minimum, например, Minimum="36" и подвигать ползунком

Элементы привязки мы поместили в приемники и в свойстве Path указали, какое именно свойство зависимости мы выбираем из источника для привязки. Свойство ContentStringFormat="F0" (здесь после F стоит ноль) в элементе Label запрещает выводить дробную часть значения ползунка. Свойство Mode="OneWay" устанавливает однонаправленный поток данных от источника ( Slider ) к приемникам ( Label и TextBlock ). Содержимое 'Simple Text' надписи последнего элемента TextBlock можно поменять местами с секцией привязки

  • Испытайте пример - функциональность вкладки Page2 получилась абсолютно одинаковой с вкладкой Page1. Разберитесь с разметкой и подивитесь простоте и мощности механизма привязки

Представление окна будет таким


Вкладка Page3. Однонаправленная привязка по синтаксису расширения разметки

  • Добавьте в контейнер TabControl файла Window1.xaml новую вкладку Page3, представленную следующей разметкой
<!-- Page3. Использование привязки по синтаксису расширения разметки -->
            <TabItem Header="Page3">
                <StackPanel>
                    <TextBlock FontSize="16" TextDecorations="Underline"
                        TextAlignment="Center" Margin="0,5,0,15" Foreground="Red"
                        Text="Привязка расширением разметки" 
                        />
                    <StackPanel Orientation="Horizontal" Margin="5">
                        <Label Width="40"
                            Content="{Binding ElementName=slider3, Path=Value, Mode=OneWay}" 
                            />
                        <Slider Name="slider3" Width="230" 
                            Minimum="11" Maximum="54"
                            TickFrequency="2" TickPlacement="BottomRight"
                            IsSnapToTickEnabled="True"
                            />
                    </StackPanel>
                    <TextBlock Margin="0,10" 
                        Foreground="Blue"
                        FontSize="{Binding ElementName=slider3, Path=Value, Mode=OneWay}"
                        Text="Simple Text"
                        />
                </StackPanel>
            </TabItem>

Привязка по синтаксису расширения разметки похожа на присоединение ресурсов по тому же синтаксису, только список параметров привязки разделяется запятыми. Примененный синтаксис привязки сильно сокращает код разметки. Этот синтаксис еще называют синтаксисом атрибута, поскольку он концентрирует код привязки данных внутри атрибута привязываемого элемента. В сущности, тег Binding помещается в фигурные скобки наравне с атрибутами элемента.

Обратите внимание, что по сравнению с примером Page2 мы убрали из атрибутов элемента Label параметр форматирования ContentStringFormat="F0", а вместо этого добавили к элементу Slider свойство IsSnapToTickEnabled="True". Такой прием заставляет свойство Value элемента Slider меняться с установленным шагом дискретности TickFrequency="2" и притягивает головку бегунка к делениям шкалы. Это побуждает элемент Label отображать значение свойства Slider.Value типа double с нулевой дробной частью как целое число.

  • Запустите приложение - вкладка Page3 представляет тот же самый результат

И опять, для вкладки Page3 мы не написали ни строчки процедурного кода!

Вкладка Page4. Множественная привязка

В элементе-приемнике мы можем привязывать к различным источникам более чем одно свойство. Вот пример

  • Добавьте в контейнер TabControl файла Window1.xaml новую вкладку Page4, представленную следующей разметкой
<!-- Page4. Множественная привязка -->
            <TabItem Header="Page4">
                <StackPanel>
                    <TextBlock FontSize="16" TextDecorations="Underline"
                        TextAlignment="Center" Margin="0,5,0,15" Foreground="Red"
                        Text="Множественная привязка" 
                        />
                    <TextBox Name="textBox4" Margin="5,0,5,15" Text="Simple Text" />
                    <StackPanel Orientation="Horizontal" Margin="5">
                        <Label Width="40"
                            Content="{Binding ElementName=slider4, Path=Value, Mode=OneWay}" 
                            />
                        <Slider Name="slider4" Width="230" 
                            Minimum="11" Maximum="54"
                            TickFrequency="2" TickPlacement="BottomRight" 
                            IsSnapToTickEnabled="True"
                            />
                    </StackPanel>
                    <ListBox Name="listBox4" Margin="5">
                        <ListBox.Resources>
                            <SolidColorBrush x:Key="redBrush" Color="Red" />
                            <SolidColorBrush x:Key="greenBrush" Color="Green" />
                            <SolidColorBrush x:Key="blueBrush" Color="Blue" />
                        </ListBox.Resources>
                        <ListBoxItem Tag="{StaticResource redBrush}" Content="Red" />
                        <ListBoxItem Tag="{StaticResource greenBrush}" Content="Green" />
                        <ListBoxItem Tag="{StaticResource blueBrush}" Content="Blue"
                            Selector.IsSelected="True" />
                    </ListBox> 
                    <TextBlock Margin="0,10" 
                        FontSize="{Binding ElementName=slider4, Path=Value, Mode=OneWay}"
                        Text="{Binding ElementName=textBox4, Path=Text, Mode=OneWay}"
                        Foreground="{Binding ElementName=listBox4, Path=SelectedItem.Tag, Mode=OneWay}"
                        />
                </StackPanel>
            </TabItem>

В данном примере мы ввели текстовое поле <TextBox> для изменения отображаемого текста, и элемент списка <ListBox>, который применили для выбора пользователем цвета. Элемент <TextBlock> мы привязали сразу к трем элементам-источникам, в которых определяется: содержимое текста, размер и цвет шрифта. Передача информации в связанных элементах осуществляется в однонаправленном режиме. Для привязки по цвету используется свойство Tag элементов списка, которое относится к типу Object.

  • Запустите приложение и испытайте работу вкладки Page4, реализующей множественную привязку. Разберитесь с кодом разметки

Вкладка будет выглядеть так


При однонаправленной привязке на стороне приемника данные источника непрерывно отражаются в приемнике. Это видно на примере поведения свойства Text элемента TextBlock, которое получает однонаправленные данные из текстового поля объекта textBox4. Далее мы увидим, что при двунаправленной привязке, когда приемник привязан к источнику в режиме Mode=TwoWay, приемник также будет получать данные источника непрерывно, но обратную отсылку при вводе данных на стороне приемника он сможет осуществить источнику только при потере фокуса. Это обусловлено значением параметра UpdateSourceTrigger=LostFocus, которое принято по умолчанию объектом Binding для обновления привязки.

Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000