При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. |
Основы технологии WPF
Ресурсы
Объектный ресурс – это .NET-объект, который определяется в одном месте, а используется в нескольких местах приложения. Данный ресурс определяется в XAML-разметке [ 4 ] , [ 8 ] .
Объектные ресурсы обладают рядом важных характеристик:
- эффективность за счет реализации принципа повторного использования кода;
- удобство сопровождения за счет переноса низкоуровневых деталей форматирования в одно центральное место;
- адаптируемость за счет появления возможности динамического изменения информации, отделенной от кода.
Каждый элемент, который наследуется от FrameworkElement (см. рис. 2.2) включает свойство Resources, в котором хранится словарная коллекция ресурсов Resourcesdictionary. В коллекции ресурсов может храниться объект любого типа. Каждый элемент имеет доступ как к ресурсам в собственной коллекции ресурсов, так и к коллекции ресурсов в коллекциях всех его родительских элементов. Чаще всего ресурсы хранятся на уровне окна или страницы для обеспечения совместного использования этих ресурсов всеми вложенными в них элементами.
Ресурсы определяются в секции Resource соответствующего элемента, например для окна следующим образом.
<Window x:Class="MyFirstWpfProject.MainWindow" ... > <Window.Resources> .... </Window.Resources> .... </Window>
Каждый ресурс записывается в следующем виде.
<ТипРесурса x:Key="КлючРесурса" > ... </ ТипРесурса >
Для задания свойств объекта ( ТипРесурса ) может использоваться синтаксис атрибутов или элементов свойств. Элементы XAML обращаются к ресурсам по ключу ( КлючРесурса ), который определяется атрибутом x:Key. Ключ ресурса задается с использованием расширения разметки StaticResource.
Например, в приложении создана градиентная кисть для заливки кнопки, которую предполагается использовать в других элементах интерфейса. Для обеспечения возможности повторного использования созданной градиентной кисти определим её как ресурс.
<Window.Resources> <LinearGradientBrush x:Key="BrushButton" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFD2E995" Offset="0.9"/> <GradientStop Color="#FF74EDB3" Offset="0.55"/> <GradientStop Color="#FF72D8A7" Offset="0.75"/> <GradientStop Color="#FF233CC6" Offset="0.25"/> </LinearGradientBrush> </Window.Resources> <StackPanel> <Button x:Name="New" Content="Создать" Width="200" Command="New" Margin="154.5,0" Background="{StaticResource BrushButton}"/> </StackPanel>
Градиентная кисть имеет тип LinearGradientBrush и для неё задан ключ BrushButton. В XAML-описании кнопки атрибут Background определяется расширением разметки { StaticResource BrushButton }.
В вышеприведенном примере используется статический ресурс. Статический ресурс извлекается из коллекции ресурсов только один раз. При этом любые вносимые в объект ресурса изменения могут быть замечены сразу же. Если в процессе функционирования приложения созданный ресурс может измениться, необходимо использовать динамический ресурс – DynamicResource. Динамический ресурс определяется в коллекции ресурсов всякий раз, когда в этом возникает необходимость.
Ресурсы могут быть определены на уровне элемента, контейнера, окна или страницы, приложения, системы или сборки.
Для повторного использования ресурсов создаются словари ресурсов. Словарь ресурсов – это XAML-файл для хранения ресурсов. Если переместить созданный ранее ресурс для градиентной кисти в словарь, то файл словаря ресурсов MyDictionary.xaml буден иметь следующий вид.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <LinearGradientBrush x:Key="BrushButton" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFD2E995" Offset="0.9"/> <GradientStop Color="#FF74EDB3" Offset="0.55"/> <GradientStop Color="#FF72D8A7" Offset="0.75"/> <GradientStop Color="#FF233CC6" Offset="0.25"/> </LinearGradientBrush> </ResourceDictionary>
Для использования словаря ресурсов его необходимо объединить с коллекцией ресурсов, например окна.
<Window.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="MyDictionary.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Window.Resources>
Объединение словаря ресурсов с ресурсами другого объекта производится через задание свойства ResourceDictionary.MergedDictionaries. Коллекция MergedDictionaries – это коллекция объектов ResourceDictionary, которые должны быть добавлены в коллекцию ресурсов. Добавляемые словари ресурсов задаются как значение атрибута Source. В рассматриваемом примере это файл словаря ресурсов MyDictionary.xaml.
Стили
Стили – это коллекция значений свойств, которые могут быть применены к элементу. Они позволяют определить общий набор характеристик форматирования и применять их по всему приложению для обеспечения согласованности. Стили в WPF могут устанавливать любое свойство зависимостей. Их можно применять для стандартизации визуального поведения каких-либо элементов. Стили WPF поддерживают триггеры, которые позволяют изменять стиль элемента при изменении других свойств. Стили позволяют использовать шаблоны для переопределения стандартного визуального представления элементов управления.
Стиль создается на базе класса Style, свойства которого приведены в табл. 2.1.
Например, в приложении необходимо многократно использовать кнопки, которые имеют светло-голубой фон и голубую рамку.
<Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Background" Value="LightBlue"/> <Setter Property="BorderBrush" Value="Blue" /> </Style>
Имя стилю задается атрибутом x:Key ( ButtonStyle ). Атрибут TargetType определяет тип, для которого будет применяться стиль ( Button ). Каждый объект Setter устанавливает в элементе одно свойство, которое обязательно должно быть свойством зависимостей. Установка свойств производится с помощью атрибутов Property, который определяет имя свойства, и Value, которое задает значение свойства.
В стиль можно добавить объект EventSetters, в котором привязывается события к определенному обработчику.
Триггеры позволяют вносить изменения в стиль при выполнении определенных условий. Добавим в стиль для кнопки ButtonStyle триггер, который будет формировать красный фон при наведении указателя мыши на кнопку.
<Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Background" Value="LightBlue"/> <Setter Property="BorderBrush" Value="Blue" /> <Style.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Background" Value="Red" /> </Trigger> </Style.Triggers> </Style>
В триггере должно быть указано идентифицирующее свойство (в нашем примере IsMouseOver ), за которым должно вестись наблюдение, и значение, которого следует ожидать (в нашем примере true ). Когда появляется необходимое значение, устанавливается свойство, которое определено объектом Setter. В приведенном примере при IsMouseOver = true, то есть наведении указателя мыши на кнопку, свойству Background присваивается значение Red, то есть фон кнопки становится красным. Когда указатель мыши покидает кнопку, условия срабатывания триггера нарушаются и фон кнопки переходит в прежнее состояние.
Кроме триггера, ожидающего изменение свойства, имеются триггеры события ( EventTrigger ), которые ожидают возникновения определенного события.