Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
WPF-практика 5 События и команды.doc
Скачиваний:
4
Добавлен:
01.07.2025
Размер:
2.21 Mб
Скачать

Реализация части обработчиков раздела меню Edit

Задачи раздела меню Edit, связанные с использованием буфера обмена, реализовать достаточно легко, поскольку вся необходимая функциональность уже заложена в элементе TextBox. Одними из первых подключим откаты Undo и Redo. Можно было бы создать свой механизм хранения откатов, но мы воспользуемся встроенным в TextBox журналом откатов. Он поддерживается методами Undo() и Redo(). Все члены класса TextBox можно посмотреть в MSDN на русском языке по ссылке

http://msdn.microsoft.com/ru-ru/library/system.windows.controls.textbox_members.aspx

Еще раз вспомним, что мы пока не управляем доступностью элементов-источников задач.

  • В файле Edit.cs заполните часть обработчиков следующим кодом

partial class Window1

{

//------------------------------------------------------

//

// Обработчики источников задач Edit

//

//------------------------------------------------------

private void UndoOnExecute(object sender, RoutedEventArgs e)

{

txtBox1.Undo();

}

private void RedoOnExecute(object sender, RoutedEventArgs e)

{

txtBox1.Redo();

}

private void CutOnExecute(object sender, RoutedEventArgs e)

{

txtBox1.Cut();

// Вариант

//Clipboard.SetText(txtBox1.SelectedText);

//txtBox1.SelectedText = "";

}

private void CopyOnExecute(object sender, RoutedEventArgs e)

{

txtBox1.Copy();

// Вариант

//Clipboard.SetText(txtBox1.SelectedText);

}

private void PasteOnExecute(object sender, RoutedEventArgs e)

{

// Если в буфере содержатся данные текстового формата

if (Clipboard.ContainsText())

txtBox1.Paste();

}

private void DeleteOnExecute(object sender, RoutedEventArgs e)

{

txtBox1.SelectedText = String.Empty;

}

private void FindOnExecute(object sender, RoutedEventArgs e)

{

}

private void FindNextOnExecute(object sender, RoutedEventArgs e)

{

}

private void ReplaceOnExecute(object sender, RoutedEventArgs e)

{

}

private void GoToOnExecute(object sender, RoutedEventArgs e)

{

}

private void SelectAllOnExecute(object sender, RoutedEventArgs e)

{

txtBox1.SelectAll();

}

}

Оставшиеся обработчики задач меню Edit требуют более сложного кода с использованием немодальных диалоговых окон, которые должны располагаться всегда поверх основного окна с редактируемым текстом. Попробуем последовательно реализовать их.

Разработка и кодирование диалогового окна Find and Replace

Создадим диалоговое окно и назначим ему в качестве владельца основное окно Window1. Окно, имеющее владельца, всегда располагается поверх него, свертывается и закрывается вместе с ним. Именно так и должно вести себя проектируемое окно Find and Replace в режиме runtime (при выполнении).

  • В панели Solution Explorer выделите узел проекта Notepad1 и командой меню Project/Add Window добавьте новое окно с именем FindAndReplaceDialog

  • Заполните файл FindAndReplaceDialog.xaml разметкой создания интерфейса диалогового окна

<Window x:Class="Notepad1.FindAndReplaceDialog"

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

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

Title="Find and Replace"

WindowStartupLocation="CenterOwner"

SizeToContent="WidthAndHeight"

ResizeMode="NoResize"

ShowInTaskbar="false"

Activated="OnActivated"

Background="{StaticResource DialogBackgroundBrush}"

>

<Grid ShowGridLines="False" >

<Grid.ColumnDefinitions>

<ColumnDefinition Width="Auto" />

<ColumnDefinition Width="Auto" />

</Grid.ColumnDefinitions>

<Grid.RowDefinitions>

<RowDefinition Height="Auto" />

<RowDefinition Height="*" />

</Grid.RowDefinitions>

<!-- Контейнер для кнопок -->

<StackPanel

Grid.Row="0"

Grid.RowSpan="2"

Grid.Column="2"

Margin="5"

>

<!-- Задаем отступы кнопок -->

<StackPanel.Resources>

<Style TargetType="{x:Type Button}">

<Setter Property="Margin" Value="3" />

</Style>

</StackPanel.Resources>

<Button

MinWidth="75"

MinHeight="23"

Name="_findNext"

IsDefault="True"

IsEnabled="False"

Click="FindNextClicked"

Content="_Find Next" />

<Button

MinWidth="75"

MinHeight="23"

Name="_replace"

Visibility="Collapsed"

Click="ReplaceClicked"

Content="_Replace" />

<Button

MinWidth="75"

MinHeight="23"

Name="_replaceAll"

Click="ReplaceAllClicked"

Visibility="Collapsed"

Content="Replace _All" />

<Button

MinWidth="75"

MinHeight="23"

Click="CancelClicked"

IsCancel="True"

Content="Cancel" />

</StackPanel>

<!-- Текстовые метки и текстовые поля в левом верхнем квадранте -->

<Grid

ShowGridLines="False"

Grid.Row="0"

Grid.Column="0"

Margin="5 10 0 0" >

<Grid.ColumnDefinitions>

<ColumnDefinition Width="Auto" />

<ColumnDefinition Width="*" />

</Grid.ColumnDefinitions>

<Grid.RowDefinitions>

<RowDefinition />

<RowDefinition />

</Grid.RowDefinitions>

<Label

Grid.Row="0"

Grid.Column="0"

VerticalAlignment="Center"

Target="{Binding ElementName=_findWhat}"

Content="Fi_nd what:" />

<TextBox

Name="_findWhat"

Grid.Row="0"

Grid.Column="1"

Width="150"

MaxLength="100"

Margin="0 5 0 5"

AcceptsReturn="False"

TextChanged="FindTextChanged" />

<Label

Name="_replaceLabel"

Grid.Row="1"

Grid.Column="0"

VerticalAlignment="Center"

Target="{Binding ElementName=_replaceWith}"

Visibility="Collapsed"

Content="Re_place with:" />

<TextBox

Name="_replaceWith"

Grid.Row="1"

Grid.Column="1"

Width="150"

MaxLength="100"

VerticalAlignment="Center"

Visibility="Collapsed"

AcceptsReturn="False" />

</Grid>

<!-- Секция установки регистра и направления поиска для замены -->

<Grid

Grid.Row="1"

Grid.Column="0"

>

<Grid.ColumnDefinitions>

<ColumnDefinition />

<ColumnDefinition />

</Grid.ColumnDefinitions>

<!-- Установка регистра -->

<CheckBox

Name="_matchCase"

Grid.Column="0"

Margin="8 0 10 10"

HorizontalAlignment="Left"

VerticalAlignment="Bottom"

IsChecked="False"

Focusable="True"

Content="Match _case" />

<!-- Группа радиокнопок направления поиска -->

<GroupBox

Name="_directionGroupBox"

Header="Direction"

Grid.Column="1"

HorizontalAlignment="Right"

Margin="0 10 0 10">

<StackPanel Orientation="Horizontal" Margin="10 20 10 10">

<RadioButton

Name="_findDown"

IsChecked="True"

Content="_Down" />

<RadioButton

Name="_findUp"

Margin="8 0 0 0"

Content="_Up" />

</StackPanel>

</GroupBox>

</Grid>

</Grid>

</Window>

В настройках окна мы устанавливаем цвет фона из статического ресурса параметром

Background="{StaticResource DialogBackgroundBrush}"

  • Обратите внимание и на другие настройки интерфейса окна и элементов

  • Добавьте в ресурсы приложения файла App.xaml следующий код

<Application x:Class="Notepad1.App"

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

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

StartupUri="FindAndReplaceDialog.xaml">

<Application.Resources>

<String xmlns="clr-namespace:System;assembly=Mscorlib" x:Key="ApplicationTitle1">

"Window1: Управление состоянием источников команд"

</String>

<String xmlns="clr-namespace:System;assembly=Mscorlib" x:Key="ApplicationTitle2">

"Window2: Управление состоянием источников команд"

</String>

<SolidColorBrush x:Key="DialogBackgroundBrush"

Color="{x:Static SystemColors.ControlColor}" />

</Application.Resources>

</Application>

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

  • Запустите приложение Notepad1 - начальный интерфейс для задачи Find должен быть таким

В настройках элементов разметки, связанных с задачей Replace, мы использовали значение атрибута Visibility=" Collapsed ". Есть еще значения Visibility=" Hidden " и Visibility=" Visible " (по умолчанию). Hidden - элемент скрыт (не отображается, но занимает место), Collapsed - элемент свернут (не отображается и не занимает место).

  • Заполните кодовую часть в файле FindAndReplaceDialog.xaml.cs следующим образом (...следующим 'светлым образом' - шутка!)

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

namespace Notepad1

{

public partial class FindAndReplaceDialog : Window

{

public FindAndReplaceDialog()

{

InitializeComponent();

// Начальная доступность кнопок, хотя кнопки Replece

_findNext.IsEnabled = _replace.IsEnabled = _replaceAll.IsEnabled

= !String.IsNullOrEmpty(_findWhat.Text);

}

#region Открытые свойства - обертки закрытых полей

//------------------------------------------------------

//

// Открытые свойства - обертки закрытых полей

//

//------------------------------------------------------

// Содержимое текстового поля _findWhat

public string FindWhat

{

get

{

return _findWhat.Text;

}

set

{

_findWhat.Text = value;

}

}

// Содержимое текстового поля _replaceWith

public string ReplaceWith

{

get

{

return _replaceWith.Text;

}

set

{

_replaceWith.Text = value;

}

}

// Определение состояния флага учета регистра

public bool? MatchCase { get { return _matchCase.IsChecked; } }

// Определение состояния радиокнопки направления поиска назад

public bool? SearchUp { get { return _findUp.IsChecked; } }

// Управление видимостью интерфейса замены

// Hidden - элемент скрыт (не отображается, но занимает место)

// Collapsed - элемент свернут (не отображается и не занимает место)

public bool ShowReplace

{

get { return _replaceWith.Visibility == Visibility.Visible; }

set

{

Visibility show;

if (value)

{

// Отобразить

show = Visibility.Visible;

_directionGroupBox.Visibility = Visibility.Collapsed;

_findDown.IsChecked = true;

}

else

{

// Свернуть

show = Visibility.Collapsed;

_directionGroupBox.Visibility = Visibility.Visible;

}

_replaceLabel.Visibility = _replaceWith.Visibility =

_replace.Visibility = _replaceAll.Visibility = show;

}

}

#endregion Общедоступные свойства - обертки полей

#region Открытые события для обработки в основном классе

//------------------------------------------------------

//

// Открытые события для обработки в основном классе Window1

// Обеспечивают взаимодействие диалогового окна с владельцем

//

//------------------------------------------------------

// Объявляем немаршрутизованные события

public event EventHandler FindNext;

public event EventHandler Replace;

public event EventHandler ReplaceAll;

#endregion Открытые события для обработки в основном классе Window1

#region Закрытые обработчики

//------------------------------------------------------

//

// Закрытые методы

// При возбуждении событий первый параметр - ссылка на диалог,

// которую в основном классе приведем к самому диалоговому окну

//

//------------------------------------------------------

void OnActivated(object sender, EventArgs e)

{

_findWhat.Focus();

}

private void FindNextClicked(object sender, RoutedEventArgs e)

{

// Если на событие подписались, возбуждаем его

if (FindNext != null)

{

FindNext(this, EventArgs.Empty);

}

}

private void ReplaceClicked(object sender, RoutedEventArgs e)

{

// Возбуждаем событие, если для него существует обработчик

if (Replace != null)

{

Replace(this, EventArgs.Empty);

}

}

private void ReplaceAllClicked(object sender, RoutedEventArgs e)

{

// Проверяем наличие обработчика и возбуждаем событие

if (ReplaceAll != null)

{

ReplaceAll(this, EventArgs.Empty);

}

}

private void CancelClicked(object sender, RoutedEventArgs e)

{

this.Close();

}

private void FindTextChanged(object sender, TextChangedEventArgs e)

{

// Управление доступность кнопок в зависимости от текстового поля

_findNext.IsEnabled = _replace.IsEnabled = _replaceAll.IsEnabled

= !String.IsNullOrEmpty(_findWhat.Text);

}

#endregion Закрытые обработчики

}

}

При щелчке на кнопках собственные обработчики кнопок возбуждают в диалоге события, которые будет прослушивать основное окно, перехватывать их и обрабатывать своими обработчиками. При объявлении свойств MatchCase и SearchUp использован тип " bool?", поскольку элементы CheckBox и RadioButton имеют три состояния: IsChecked=" False ", IsChecked=" True " и IsChecked=" {x:Null} ". Для выборки только булевых состояний при программном управлении в клиентском коде этими элементами через открытые свойства нужно будет применять явное приведение типов. Например, caseFlag=(bool)_dlg.MatchCase;, где _dlg - это экземпляр класса FindAndReplaceDialog в клиенте.

  • Запустите приложение для проверки отсутствия синтаксических ошибок