- •А.А. Волосевич
- •1. ОбщееописаниеWpf
- •2. ПРостейшее ПриложениеWpf
- •4. Базовые концепции wpf Иерархия классов
- •Свойства зависимостейи присоединённые свойства
- •Маршрутизируемыесобытия
- •Многопоточность в wpf
- •5. СтруктуРа Оконного приложения wpf
- •Класс Window
- •КлассApplication
- •6. Компоновка
- •Размер и выравнивание
- •Основные контейнеры компоновки
- •Прокрутка и декорирование содержимого
- •7. Обзор элеменТов управления
- •Цвета и окантовка:
- •Шрифт содержимого:
- •Элементы управления содержимым
- •Списковые элементы управления
- •Прочие элементы управления
- •8. Фигуры
- •9. Цвет,кисти, прозрачность Представление цвета в wpf
- •Лучшие кисти
- •Прозрачность
- •10. Трансформации и эффекты
- •11. Классы drawing иvisual
- •12. Ресурсы
- •Двоичные ресурсы
- •Логические ресурсы
- •13. Привязка данных Базовые концепции привязки данных
- •Практическое использование привязки данных
- •Конвертеры значений
- •Проверка данных
- •14. Стилии триггеры
- •15. ПрИвязкакколлекциямиШаблоныданных
- •16. Представления Данных
- •17. ШАблоны элементов управления
Практическое использование привязки данных
Построим примерразметки XAML, в котором привязка соединяет два свойства разных элементов управления.Для привязки данных определено расширения разметки {Binding}, что позволяет настроить привязку декларативно.Сделаем так, чтобы при перемещении ползунка слайдера автоматически менялся размер строки текста1:
<StackPanel>
<Slider Name="slider" Margin="3" Minimum="1" Maximum="40" />
<TextBlock Margin="10" Text="Sample Text" Name="lblText"
FontSize="{Binding ElementName=slider, Path=Value}"/>
</StackPanel>
Рис. 36. Привязка для элементов управления.
Привязку можно выполнить не только декларативно, но и программно (а в некоторых ситуациях это единственный вариант). Нижеприведёнкодпрограммнойпривязки, эквивалентной примеру разметки XAML:
Binding binding = newBinding();
binding.Source = slider;
binding.Path = newPropertyPath("Value");
lblText.SetBinding(TextBlock.FontSizeProperty, binding);
Заданную привязку можно удалить в коде, используя два статических метода класса BindingOperations. Метод ClearBinding() принимает ссылку на свойство зависимостей, которое имеет привязку, подлежащую удалению, аClearAllBindings() удаляет все привязки элемента:
BindingOperations.ClearAllBindings(lblText);
Следующий пример XAMLдемонстрирует двунаправленную привязку: при перемещении ползунка слайдера меняется текст в TextBox, акорректное изменение текста (допустимы вещественные числа) ведёт к перемещению ползунка. Обратите внимание на установкуUpdateSourceTrigger=PropertyChanged.Это обеспечивает мгновенные изменения позиции ползунка прямо при вводе текста.
<StackPanel>
<Slider Name="slider" Minimum="1" Maximum="40" Value="10" />
<TextBox Name="txtSize"
Text="{Binding ElementName=slider, Path=Value,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
ЕслиUpdateSourceTriggerустановитьвUpdateSourceTrigger.Explicit, требуетсянаписатькод, вызывающийдляобновленияметодUpdateSource()уобъектаBindingExpression, связанногосэлементом:
// получить выражение привязки для текстового поля
BindingExpression binding =
txtSize.GetBindingExpression(TextBox.TextProperty);
// обновитьсвязанныйисточник (Slider)
binding.UpdateSource();
Рассмотрим сценарии, в которых источником привязки является не элемент WPF, а обычный объект. В этом случае вместо ElementName используется одно из описанных ниже свойств:
Source– свойство привязки, указывающее на объект-источник.
RelativeSource– свойство привязки, которое указывает на источник относительно текущего элемента. Это подход, часто применяемый при разработке шаблонов элементов управления и шаблонов данных.
DataContext– наследуемое свойство FrameworkElement.Если источник не указан через Source или RelativeSource, WPF выполняет поиск по дереву элементов, начиная с текущего элемента. В качестве источника данных будет использоваться первый DataContext, не равный null.
Следующий пример разметки XAMLдемонстрирует использование свойства Sourceдля связывания с объектом класса Person. Так как объект-источник должен существовать на момент выполнения привязки, этот объект помещается в словарь ресурсов окна.
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication">
<Window.Resources>
<local:Person x:Key="person" Name="Mr. Smith" Age="27.3" />
</Window.Resources>
<StackPanel>
<TextBox Text="{Binding Source={StaticResource person},
Path=Name}"/>
</StackPanel>
</Window>
publicclassPerson
{
publicstring Name { get; set; }
publicdouble Age { get; set;}
publicstring Address { get; set; }
}
Модификация примера использует для размещения объекта привязки свойство DataContext у контейнера StackPanel:
<!--пропущена настройка окна и объявление ресурса1-->
<StackPanel DataContext="{StaticResource person}">
<TextBox Text="{BindingName}"/>
</StackPanel>
Свойство привязки RelativeSource позволяет указать объект-источник на основе его отношения к целевому объекту. Например, можно использовать RelativeSource для привязки элемента к самому себе или к родительскому элементу, находящемуся на неизвестное число шагов вверх по дереву элементов.Для установки свойства Binding.RelativeSourceиспользуется объект класса RelativeSource. При этом можно использовать как специальное расширение разметки, так и синтаксис, основанный на элементах-свойствах.
<!--используем элемент-свойствоXAML-->
<TextBlock>
<TextBlock.Text>
<Binding Path="Title">
<Binding.RelativeSource>
<RelativeSource Mode="FindAncestor"
AncestorType="{x:Type Window}" />
</Binding.RelativeSource>
</Binding>
</TextBlock.Text>
</TextBlock>
<!--используемрасширениеразметки -->
<TextBlock Text="{Binding Path=Title,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}" />
В табл. 13 перечислены четыре возможных режима для RelativeSource.
Таблица 13
Значения перечисления RelativeSourceMode
Имя |
Описание |
Self |
Выражение привязывает к другому свойству того же элемента |
FindAncestor |
Выражение привязывает к родительскому элементу. WPF будет производить поиск вверх по дереву элементов, пока не найдёт нужного родителя. Чтобы специфицировать родителя, необходимо также установить свойство AncestorType для указания типа родительского элемента. Можно использовать свойство AncestorLevel, чтобы пропустить определённое число вхождений указанного элемента |
PreviousData |
Выражение привязывает к предыдущему элементу данных в списке |
TemplatedParent |
Выражение привязывает к элементу, к которому применён шаблон. Этот режим работает, только если привязка расположена внутри шаблона элемента управления или шаблона данных |
Если при привязке к объекту .NETнеобходимо, чтобы привязка отслеживала изменения в объекте, можно поступить одним из следующих способов:
Сделать отслеживаемые свойства объекта-источника свойствами зависимостей, а сам объект наследовать от DependencyObject.
Инициировать при изменении свойства события ИмяСвойстваChanged.
Реализовать в объекте-источникеинтерфейс INotifyPropertyChanged, содержащий событиеPropertyChanged. Это событие нужно инициировать всякий раз, когда свойство изменяется, передавая имя свойства.
Ниже приведена реализация класса Person, использующая третий подход:
publicclassPerson : INotifyPropertyChanged
{
publiceventPropertyChangedEventHandler PropertyChanged;
protectedvirtualvoid OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this,
newPropertyChangedEventArgs(propertyName));
}
privatestring _name;
publicstring Name
{
get {return _name}
set{
if (value != _name)
{
_name = value;
OnPropertyChanged("Name");
}
}
} // остальные свойства надо реализовать аналогично
}