- •Лабораторная работа: События и команды в wpf
- •Обзор библиотечных событий
- •Упражнение 1. Обработка событий клавиатуры
- •События мыши
- •Упражнение 2. Прослушивание событий мыши
- •Упражнение 3. Создание и прослушивание пользовательского события
- •Обработчики уровня класса
- •Добавление информации в объект аргумента события
- •Задание для Упражнения 3
- •Модель команд
- •Объекты команд
- •Библиотечные классы команд
- •Присоединение команды к источнику
- •Привязка команды к прослушивающему элементу
- •Упражнение 4. Привязка команд в разметке
- •Перекрытие функций диспетчеризации событий
- •Прямой вызов команд
- •Упражнение 5. Привязка команд в процедурном коде
- •Жесты как источники команд
- •Добавление жестов в команду
- •Способ 1
- •Способ 2
- •Способ 3
- •Добавление жестов в прослушивающий элемент
- •Упражнение 6. Разработка простого блокнота без механизма команд
- •Создание главного меню
- •Добавление иконок
- •Создание логических ресурсов
- •Создание панели инструментов, строки состояния и рабочей области
- •Замена встроенного контекстного меню
- •Назначение ресурсов неразделяемыми
- •Замена иконок на прозрачные
- •Отключение встроенных команд
- •Подключение иконки приложения
- •Распределение класса по нескольким файлам и создание вспомогательных функций
- •Размещение вариантов заголовков окна в ресурсах приложения
- •Создание заготовок обработчиков
- •Регистрация обработчиков в разметке
- •Реализация обработчиков раздела меню File
- •Обработка системной кнопки
- •Реализация части обработчиков раздела меню Edit
- •Разработка и кодирование диалогового окна Find and Replace
- •Кодирование функциональности Find and Replace в основном окне
- •Подключение функциональности Find and Replace к источникам задач
- •Разработка диалогового окна Go To
- •Применение вложенных ресурсов
- •Подключение функциональности Go To к основному окну
- •Прочие задачи
- •Принудительная перерисовка окна
- •Добавление жестов
- •Логика отключения источников задач
- •Реализация логики отключения источников задачи Save
- •Упражнение 7. Разработка простого блокнота с использованием механизма команд
- •Создание нового проекта из копии существующего
- •Краткий анализ задачи
- •Создание и привязка команд
- •Реализация логики доступности источников команд
- •Отображение позиции курсора в строке состояния
Привязка команды к прослушивающему элементу
Как только мы присоединим команду к элементу-источнику, он сразу же становится недоступен, как будто бы его свойство IsEnabled приобрело значение false. Это происходит потому, что мы не привязали команду к прослушивающему ее элементу. Как же это сделать?
Любой элемент управления WPF наследует от класса System.Windows. UIElement, который имеет свойство-коллекцию CommandBindings типа CommandBindingCollection, предназначенную для того, чтобы можно было сделать этот элемент прослушивающим команды. В эту коллекцию помещаются специальные объекты привязки CommandBinding, у которых имеется свойство Command и событие Executed. Мы создаем объекты CommandBinding, присоединяем к их свойству Command нужные объекты команд, а к событию Executed - соответствующие обработчики. Затем эти настроенные объекты добавляем в коллекцию CommandBindings элемента. Так элемент становится прослушивающим.
Как уже говорилось, когда источник команды возбуждает присоединенный к нему объект команды, тот последовательно выполняет методы CanExecute() и Execute() интерфейса ICommand. Эти методы генерируют командные события, которые движутся по дереву элементов, проверяя их коллекции CommandBindings с целью обнаружить объект CommandBinding, соответствующий возбужденной команде. Как только такой объект привязки будет обнаружен в прослушивающем команду элементе, немедленно выполнится подписанный на событие Executed обработчик.
В качестве прослушивающего можно сделать любой элемент логического дерева. Но для получения наибольшей гибкости привязки команд рекомендуется добавлять в корневой элемент - окно (или контейнер элемента Page ).
Упражнение 4. Привязка команд в разметке
Построим простое приложение, в котором присоединим библиотечные команды ApplicationCommands. Open и ApplicationCommands. Save, каждую - к двум элементам-источникам: кнопке и главному меню окна. Дополнительным источником команд будет уже встроенная в них клавиатурная комбинация Ctrl+O и Ctrl+S. В качестве прослушивающего элемента выберем окно. В коллекцию CommandBindings окна добавим два объекта привязки CommandBinding, связывающие между собой команду и обработчик. Привязку выполним в разметке XAML.
Добавьте к решению командой оболочки File/Add/New Project новый проект с именем BindingCommandsXAML и назначьте его стартовым в панели Solution Explorer командой контекстного меню Set as StartUp Project
увеличить изображение
Заполните файл разметки Window1.xaml следующим кодом
<Window x:Class="BindingCommandsXAML.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1: Декларативная привязка" Height="300" Width="300"
Background="#FFD4D0C8"
WindowStartupLocation="CenterScreen"
>
<StackPanel Margin="5">
<Menu>
<MenuItem Header="_File">
<MenuItem Command="ApplicationCommands.Open" />
<MenuItem Command="ApplicationCommands.Save" />
</MenuItem>
</Menu>
<Button Margin="5" Padding="5" Focusable="False"
Command="ApplicationCommands.Open"
Content="Open"
/>
<Button Margin="5" Padding="5" Focusable="False"
Command="ApplicationCommands.Save"
Content="Save"
/>
</StackPanel>
</Window>
Мы присоединили к интерфейсным элементам объекты команд и сделали их таким образом источниками этих команд.
Запустите проект и убедитесь, что источники команд не получают фокус ввода и являются недоступными
Несмотря на то, что в элементах меню нами не были заданы атрибуты Header, команды сами прописали нужные названия команд и добавили подсказки для горячих клавиш.
Добавьте в разметку объекты привязки следующим образом
<Window x:Class="BindingCommandsXAML.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1: Декларативная привязка" Height="300" Width="300"
Background="#FFD4D0C8"
WindowStartupLocation="CenterScreen"
>
<Window.CommandBindings>
<CommandBinding
Command="ApplicationCommands.Open"
Executed="OpenCommand_Executed">
</CommandBinding>
<CommandBinding
Command="ApplicationCommands.Save"
Executed="SaveCommand_Executed">
</CommandBinding>
</Window.CommandBindings>
<StackPanel Margin="5">
<Menu>
<MenuItem Header="_File">
<MenuItem Command="ApplicationCommands.Open" />
<MenuItem Command="ApplicationCommands.Save" />
</MenuItem>
</Menu>
<Button Margin="5" Padding="5" Focusable="False"
Command="ApplicationCommands.Open"
Content="Open"
/>
<Button Margin="5" Padding="5" Focusable="False"
Command="ApplicationCommands.Save"
Content="Save"
/>
</StackPanel>
</Window>
Вызовите контекстное меню для записей привязки обработчиков и командой Navigate to Event Handler создайте заготовки обработчиков в файле процедурного кода
Запустите приложение и убедитесь, что источники команд стали доступными, хотя обработчики еще пустые
В меню оболочки командой Project/Add Reference добавьте к текущему проекту ссылку на библиотечную сборку System.Windows.Forms.dll
Мы уже обсуждали ранее, что нельзя напрямую размещать в окне WPF интерфейсные элементы Windows Forms, для этого предназначен переходной контейнер <WindowsFormsHost>. Но в нашем случае мы будем открывать самостоятельные диалоговые окна Windows Forms и не собираемся смешивать в одном окне интерфейсные элементы из разных технологий.
Дополните в процедурном файле Window1.xaml.cs класс Window1 следующим кодом
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
// Обработчик команды Open
System.Windows.Forms.OpenFileDialog openFileDialog = null;
private void OpenCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (openFileDialog == null)
openFileDialog = new System.Windows.Forms.OpenFileDialog();
openFileDialog.ShowDialog();
this.Focus();
}
// Обработчик команды Save
System.Windows.Forms.SaveFileDialog saveFileDialog = null;
private void SaveCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (saveFileDialog == null)
saveFileDialog = new System.Windows.Forms.SaveFileDialog();
saveFileDialog.ShowDialog();
this.Focus();
}
}
Запустите приложение и испытайте возможность запуска каждой команды через любой из трех источников: кнопку, меню или клавиатурную комбинацию
Рекомендуется при совместном использовании библиотек WPF и Windows Forms не подключать пространство имен System.Windows.Forms в инструкции using, а использовать полное имя требуемых классов Windows Forms, что мы и сделали. Это нужно для того, чтобы избежать конфликта имен, поскольку в библиотеках разных технологий встречаются типы с одинаковыми именами, например, Color, Pen, Brush.
