Привязка команд и элементов

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

Продолжим дорабатывать наш текстовый редактор. Для того чтобы увидеть принцип работы с командами добавим следующую функциональность. У любого текстового редактора должна быть кнопка сохранения текста в файл, причём эта кнопка должна быть доступна лишь в том случае, если в текстовом поле что-то введено, что логично, иначе сохранять нечего. Да, в Word’e можно сохранить пустой документ, но в нашем случае важно именно условие, при котором сохранение должно быть недоступно.

Как я уже говорил, в WPF весь функционал приложения должен быть поделён на команды, одну команду можно назначать разным пользовательским элементам. Те, кто работал над созданием WPF уже создали стандартный набор команд приложения, который включает такие команды как: New, Exit, Cut, Copy… Среди этих команд имеется и команда Save. Все эти команды находятся в статическом классе ApplicationCommands. Тем не менее, у каждого приложения своя логика обработки этих команд, это значит что нам нужно создавать свою логику для того, чтобы данная команда работала так, как необходимо нашему приложению. Любая команда может быть активной, и не активной, в неактивном положении, элемент интерфейса, к которому привязана команда, должен автоматически становиться недоступным для нажатия, это очень удобно.

Для того, чтобы команда сама понимала, когда ей становиться активной, а когда – нет, у команды имеются события CanExecute и Execute. Сначала возникает событие CanExecute, здесь должна быть определена какая то логика, которая проверяет правильность пользовательского ввода, или что-то иное. И только когда CanExecute отработает до конца, сработает событие Execute.
Перейдём в *.cs файл. В свободном месте добавим два обработчика событий:

void canExecute_Save(object sender, CanExecuteRoutedEventArgs e) { } void execute_Save(object sender, ExecutedRoutedEventArgs e) { }


Пока они совершенно пустые, логику внутри обработчиков мы реализуем позже. В конструкторе окна MainWindow добавим следующий код:

public MainWindow() { InitializeComponent(); CommandBinding saveCommand = new CommandBinding(ApplicationCommands.Save, execute_Save, canExecute_Save); CommandBindings.Add(saveCommand); }


У окна имеется коллекция команд CommandBindings, соответственно, если мы добавляем окну свою команду, то необходимо её добавить в коллекцию CommandBindings. Но перед этим мы создали экземпляр класса CommandBinding, и проинициализировали его, прописав в виде первого аргумента тип команды (ApplicationCommands.Save), а во втором и третьем аргументах указали, какие обработчики событий использовать для Execute и CanExecute.
Теперь пришла пора добавить код в обработчики, но перед этим перейдём в Xaml разметку и назначим имя текстовому полю:

<TextBox Margin="4" VerticalScrollBarVisibility="Auto" Name="inputTextBox"/>


В противном случае, мы к нему не сможем обратиться из cs-кода.
Первым делом реализуем canExecute:

void canExecute_Save(object sender, CanExecuteRoutedEventArgs e) { if (inputTextBox.Text.Trim().Length > 0) e.CanExecute = true; else e.CanExecute = false; }


Главным объектом здесь является аргумент e. Он имеет свойство CanExecute булевого типа, если CanExecute равен истине, значит, команда будет доступна, в ином случае команда недоступна.
Мы делаем проверку, если в текстовом поле введено что-то, то команда будет доступна. Использование Trim даёт возможность убрать пробелы в начале и конце строки.
Перейдём к Execute обработчику:

void execute_Save(object sender, ExecutedRoutedEventArgs e) { System.IO.File.WriteAllText("textFile.txt", inputTextBox.Text); MessageBox.Show("Файл был успешно сохранён"); }


В принципе, можно было бы обойтись одним MessageBox’ом, но я добавил и сохранение в файл.
Отлично, команда создана, как бы нам теперь её назначить элементу управления. Перейдём в Xaml, найдём кнопку, отвечающую за сохранение. У большинства пользовательских элементов имеется свойство Command, которое отвечает за команду, на которую реагирует элемент. В данном случае нам нужно в качестве команды прописать Save. Взглянув на меню, я понял, что у нас нет кнопки для сохранения, в качестве варианта можно последнюю кнопку, у которой ToolTip=Вставить, переделать под сохранение:

<Button ToolTip="Сохранить" Command="Save">


Вы должны заметить, что только добавив в Command Save, кнопка поменяет цвет, таким образом, по умолчанию, CanExecute установлен в false. На рис.1. виден данный эффект.



Рисунок 2. Команда и привязанная к ней кнопка в неактивном состоянии.

Нажмём F5, скомпилировав приложение, кнопка недоступна для нажатия. Как только вводим символ в текстовое поле, кнопка должна разблокироваться. Причём, пробелы в начале строки символами не считаются, потому что такую логику мы реализовали в обработчике CanExecute.

Привязка элементов.


В WPF помимо привязки команд имеются и другие привязки, среди которых есть привязка элементов. Привязка элементов весьма полезная вещь, позволяет настроить реакцию пользовательского элемента на изменение состояния другого элемента. Допустим, мы хотим сделать увеличение шрифта в поле ввода. Мы могли бы с лёгкостью прописать необходимый код в cs части, но WPF даёт возможность реализовать это не залезая в cs файл, а обойдясь только файлом разметки.
Итак, добавим элемент Slider на панель, где у нас находится кнопка «Ок». Xaml код DockPanel’и, с находящейся внутри кнопкой примет вид:

<DockPanel Margin="5" Grid.Row="1" HorizontalAlignment="Right"> <Label Content="Размер шрифта:"></Label> <Slider Margin="4" MinWidth="100" Name="fontSlider" Maximum="100" Minimum="12"></Slider> <Button Style="{StaticResource okButtonStyle}" Content="Ok"/> </DockPanel>


Заметьте, что мы дали имя слайдеру и назначили максимальное значение равное 100 и минимальное значение. Далее необходимо найти в разметке поле ввода и изменить его Xaml:

<TextBox Margin="4" VerticalScrollBarVisibility="Auto" Name="inputTextBox" FontSize="{Binding ElementName=fontSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}"/>


Если разбирать код, то видно, что свойству FontSize назначается привязка, в ElementName мы указывает тот элемент, откуда мы будем брать значения, в Path указываем свойство элемента, где хранится значение, UpdateSourceTrigger назначает режим обновления привязки, в нашем случае, как только слайдер сдвинется с места, привязка сработает у текстового поля.
Теперь, введя что- то в текстовое поле и изменив положение слайдера, шрифт должен увеличиваться в зависимости от значения Value элемента (рис.2.)



Рисунок 2. Привязка свойств пользовательского элемента.

В моём цикле статей я сделал попытку заинтересовать вас весьма перспективной технологией WPF, то что я показал является только крошечной долей возможностей данной технологии. Пытаясь уместить в эти 5 статей самое необходимое, возможно, я обделил вниманием какой то важный аспект, тем не менее, я пытался показать вам то, что меня в дни обучения WPF очень удивило/привлекло, и заставило продолжить изучение. Ведь если технология не даёт ничего нового, то ценность её весьма сомнительна, к WPF данный факт не относится. За то малое время, которое прошло с рождения WPF и по сей день, от версии к версии Net.Framework’a добавляются и новые возможности к WPF, в то время как эра WinForms, если судить по нововведениям в Net.Framework’ах, похоже, приходит к концу. Так что выбор за вами, не стоит рассчитывать что WinForms завтра отомрёт, но тем не менее если это случится, нужно быть готовым к быстрому переходу на альтернативу – WPF.
Как я говорил, я показал лишь малую часть возможностей технологии, а потому, вне зависимости от исходов StepByStep, данный цикл статей будет продолжен.

 

 



/footer.php"; ?>