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

Ресурсы в WPF

< Самостоятельная работа 12 || Самостоятельная работа 13: 123456 || Лекция 1 >
Аннотация: WPF предлагает новую систему ресурсов, которые называют по разному (название еще не устоялось): локальными, объектными, декларативными, логическими или, просто, ресурсами. Наряду с этим новым механизмом существуют и прежние ресурсы - встраиваемые ресурсы сборок, которые в данной работе не рассматриваются.

Все необходимые для выполнения данной работы программы можно найти в прилагаемом каталоге.

Три важнейших класса:

  1. System.Windows.FrameworkElement
  2. System.Windows.FrameworkContentElement
  3. System.Windows.Application

содержат свойство Resources типа System.Windows.ResourceDictionary. Соответственно, поскольку большинство элементов управления WPF наследуют от этих классов, то любой из них содержит свою коллекцию Resources как экземпляр класса-словаря ResourceDictionary, которую можно наполнить. Ресурсы, определенные в элементе, доступны только этому элементу и его потомкам.

Чаще всего ресурсы определяют в коллекции корневого элемента-окна <Window.Resources> или в коллекции приложения <Application.Resources>. Там их разработчику привычнее найти и область видимости таких ресурсов распространяется на все дочерние элементы, то есть на все визуальное дерево. По умолчанию, если не принимать специальных мер, ресурсы окна невидимы в других окнах приложения, а ресурсы одного приложения (сборки) видимы во всех его окнах, но невидимы в других сборках.

Ресурсы представляют собой XAML -эквивалент создания констант в коде (константных переменных или полей). Они позволяют определить объект любого типа один раз, а затем многократно использовать его в коде по мере необходимости, чаще всего - для настройки визуальных элементов пользовательского интерфейса. Помещенная в ресурсы информация отделяется от процедурного кода, но может этим кодом избирательно фильтроваться в зависимости от предпочтений пользователя, культуры, текущего региона или настроек операционной системы. Для различных культур и свойств можно использовать различные коллекции ресурсов, настраивающих интерфейс.

Каждому объекту, задекларированному (определенному) как ресурс, необходимо задать значение свойства x:Key. Префикс 'x:' означает пространство имен XAML, а не пространство имен WPF. Свойство x:Key означает имя, по которому другие элементы WPF будут получать доступ к ресурсу. Это свойство должно быть уникальным не во всем приложении, а лишь в той коллекции-словаре, где определено. Имена ресурсов определяются с учетом регистра.

При синтаксическом разборе ссылки на ресурс в XAML, синтаксический анализатор XAML ( парсер XAML, parse - разбор, разбирать) выполняет поиск ресурса с соответствующим ключем вначале в словаре текущего элемента, подключающего ресурс. Если ресурс не был найдет, поиск последовательно продолжается в словарях родителей элемента в направлении к корню визуального дерева окна, а затем в словаре приложения и далее - в присоединенных сборках или ресурсах системы. Если ресурс нигде не был найден, выдается исключение XamlParseException.

Упражнение 1. Использование коллекций ресурсов

В этом упражнении мы рассмотрим особенности использования объектных ресурсов на этапе проектирования в разметочной части (декларативный режим) и управление ими в кодовой части (режим runtime ). Код упражнения построим так, чтобы он иллюстрировал по возможности больше разных сторон работы с объектными ресурсами. Вначале приведем работоспособный код, а потом его разберем.

Многие студенты, выполняя работы по WPF или ASP.NET в среде проектирования Visual Studio, где разметочная часть класса окна представлена вкладками Design и XAMLASP.NET: вкладками Design, Split и Source, а еще раньше - Design и HTML ), не пользуясь режимом Design, все же оставляют частично эту вкладку открытой. То же самое происходит и с ненужными в данный момент выдвижными панелями оболочки. Ничего иного, как занять полезное место на экране, эта вкладка нам не дает, поскольку мы в основном работаем только с дескрипторным кодом. Поэтому, лучше полностью раскрыть вкладку XAML на весь экран, пользы будет больше. А режим Design оставим дизайнеру, домохозяйке или "будущему программисту Васе". Хотя сами туда тоже иногда будем заглядывать (для справки).

Размещение ресурсов в коллекции окна

  • Создайте новое решение с именем Resources командой File/New/Project и новый проект с именем UseResource
  • Добавьте к корню проекта UseResource новую папку Images и скопируйте в нее контекстной командой Add/Existing Item из прилагаемого к работе каталога Source три рисунка, как показано на снимке

  • Выделяя последовательно эти файлы рисунков, установите (или проверьте) в панели Properties для них следующие свойства
    • FACE02.ICO, FACE04.ICO:
      • Build Action=Resource
      • Copy to Output Directory=Do not copy
    • 10440.jpg:
      • Build Action=None
      • Copy to Output Directory=Copy if newer

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

  • Откройте файл App.xaml и добавьте в коллекцию ресурсов приложения объект SolidColorBrush со следующими настройками
<Application x:Class="UseResource.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <!-- Определение ресурсов в коллекции приложения -->
    <Application.Resources>
        <SolidColorBrush x:Key="ControlColorBrush" 
                         Color="{x:Static SystemColors.ControlColor}" />
    </Application.Resources>
</Application>

Цвет для настройки помещаемого в ресурсы объекта SolidColorBrush извлекается из принадлежащего WPF статического свойства ControlColor статического класса SystemColors. Этот ресурс мы используем в параметрах окна для задания его цвета фона. В дальнейшем мы более подробно рассмотрим механизм использования статических свойств и полей в объектных ресурсах, а пока заметим, что псевдоним x в строке

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

отображает пространство имен WPF на разметку для синтаксического анализатора XAML.

  • Заполните файл Window1.xaml следующим содержимым (разметка файла приводится полностью)
<Window x:Class="UseResource.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="UseResource" 
    MinHeight="300" 
    MinWidth="300"
    Height="300" 
    Width="300"
    WindowStartupLocation="CenterScreen"
    Background="{StaticResource ControlColorBrush}">
        
    <!-- Определение ресурсов в коллекции окна -->
    <Window.Resources>
    <TextBlock x:Key="Title1" 
               TextAlignment="Center"
               Text="1. Модификация объекта ресурса"
               FontSize="14" FontWeight="Bold" 
               FontFamily="Arial"
               FontStyle="Italic" 
               TextDecorations="Underline"
               Foreground="DarkViolet"
               />
    <SolidColorBrush x:Key="ForegroundBrush1" 
                     Color="Blue" />
    <ImageBrush x:Key="BackgroundBrush1" 
                TileMode="Tile" 
                ViewportUnits="Absolute" 
                Viewport="0 0 10 10"
                ImageSource="Images/FACE02.ICO" 
                Opacity="0.5" 
                />
    
    <TextBlock x:Key="Title2"
               TextAlignment="Center"
               Text="2. Полная замена объекта ресурса"
               FontSize="14" 
               FontWeight="Bold" 
               FontFamily="Arial"
               FontStyle="Italic" 
               TextDecorations="Underline"
               Foreground="DarkViolet"
               />
    <SolidColorBrush x:Key="ForegroundBrush2" 
                     Color="Red" 
                     />
    <ImageBrush x:Key="BackgroundBrush2" 
                TileMode="Tile" 
                ViewportUnits="Absolute" 
                Viewport="0 0 24 24"
                ImageSource="Images/FACE04.ICO" 
                Opacity="0.3" 
                />
    </Window.Resources>
    
    <!-- Содержимое окна -->
    <StackPanel>
        <!-- Это не ресурс, а элемент визуального дерева -->
        <TextBlock HorizontalAlignment="Center"
                   FontSize="18"
                   FontWeight="Bold"
                   Margin="0,0,0,5">
            Применение ресурсов
        </TextBlock>
        <!-- Синтаксис подключения ресурсов 'как элемента свойства' -->
        <Label HorizontalAlignment="Center">
            <Label.Content>
                <StaticResource ResourceKey="Title1" />
            </Label.Content>
        </Label>
        <Button Name="btn1" Padding="5" Margin="5"
                FontWeight="Bold" FontSize="16" >
            <Button.Foreground>
                <DynamicResource ResourceKey="ForegroundBrush1" />
            </Button.Foreground>
            <Button.Background>
                <DynamicResource ResourceKey="BackgroundBrush1" />
            </Button.Background>
            Использует DynamicResource
        </Button>
        <Button Name="btn2" Padding="5" Margin="5" 
                FontWeight="Bold" FontSize="16" >
            <Button.Foreground>
                <StaticResource ResourceKey="ForegroundBrush1" />
            </Button.Foreground>
            <Button.Background>
                <StaticResource ResourceKey="BackgroundBrush1" />
            </Button.Background>
            Использует StaticResource
        </Button>
    
        <!-- Синтаксис подключения ресурсов 'как расширения разметки' -->
        <Label HorizontalAlignment="Center"
               Content="{StaticResource ResourceKey=Title2}" />
        <Button Click="btn3_Click" Padding="5" Margin="5" 
                FontWeight="Bold" FontSize="16"
                Foreground="{DynamicResource ResourceKey=ForegroundBrush2}" 
                Background="{DynamicResource ResourceKey=BackgroundBrush2}">
            Использует DynamicResource
        </Button>
        <!-- Упрощенный синтаксис без указания ResourceKey -->
        <Button Click="btn4_Click" Padding="5" Margin="5" 
                FontWeight="Bold" FontSize="16" 
                Foreground="{StaticResource ForegroundBrush2}" 
                Background="{StaticResource BackgroundBrush2}">
            Использует StaticResource
        </Button>
    </StackPanel>
</Window>

Представление разметки в режиме Design на данном этапе должно выглядеть так


< Самостоятельная работа 12 || Самостоятельная работа 13: 123456 || Лекция 1 >
Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №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