Кодирование функциональности Find and Replace в основном окне

Теперь нужно подключить диалоговое окно Find and Replace к основному окну Window1 для совместной работы и наделить его соответствующей функциональностью. Но прежде надо вновь назначить Window1 стартовым окном приложения.

  • Откройте файл App.xaml приложения Notepad1 и внесите изменения в открывающий дескриптор:
Было StartupUri="FindAndReplaceDialog.xaml" Стало StartupUri="Window1.xaml"

Поскольку код программного управления диалоговым окном Find and Replace будет несколько великоват, разместим его в отдельном файле с именем EditFind.cs.

  • В панели Solution Explorer выделите узел проекта Notepad1 и вызовите командой меню Project/Add New Item одноименное диалоговое окно оболочки, которое настройте так


увеличить изображение

>

После щелчка на кнопке Add мастер добавит пустой файл в текущий проект решения.

  • Заполните файл EditFind.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.Navigation;using System.Windows.Shapes; namespace Notepad1{ partial class Window1 { internal FindAndReplaceDialog _dlg = null; // Для видимости в обработчиках string _findString, _replaceString; // Для видимости в обработчиках void CreateDialog() { if (_dlg!= null)// Уже существует { // Если есть выделенное, обновляем прежнее if (!String.IsNullOrEmpty(txtBox1.SelectedText)) _findString = _dlg._findWhat.SelectedText = txtBox1.SelectedText; _dlg._findWhat.Focus(); return; } // Создать заново _dlg = new FindAndReplaceDialog(); _dlg.Owner = this; // Привязываем диалог к владельцу _dlg.Show();// Немодальное, поэтому не перехватывает управление // Продолжаем настраивать _dlg._findWhat.Focus(); // Если есть выделенное, обновляем прежнее if (!String.IsNullOrEmpty(txtBox1.SelectedText)) _findString = _dlg._findWhat.SelectedText = txtBox1.SelectedText; _dlg.ReplaceWith = _replaceString; // Анонимные обработчики _dlg.FindNext += delegate(object sender, EventArgs args) { FindNextExec(); }; //!!! _dlg.Replace += delegate(object sender, EventArgs args) { ReplaceExec(); }; //!!! _dlg.ReplaceAll += delegate(object sender, EventArgs args) { // У Петцольда (WPF с.466) есть иной вариант этого обработчика _replaceString = _dlg.ReplaceWith; txtBox1.SelectionStart = 0; txtBox1.SelectionLength = 0; while (FindNextExec()) { using (txtBox1.DeclareChangeBlock()) { txtBox1.SelectedText = _replaceString; txtBox1.SelectionLength = _replaceString.Length; } } txtBox1.SelectionStart = 0; txtBox1.SelectionLength = 0; }; //!!! _dlg.Closed += delegate(object sender, EventArgs args) { _dlg = null; }; //!!! Точка с запятой обязательна - заканчивает строку } bool FindNextExec() { int indexStart, indexFind;// Откуда начать и начало следующего _findString = _dlg.FindWhat; // Извлекаем текст поиска // Учет регистра при поиске, однострочный условный оператор StringComparison strComp = (bool)_dlg.MatchCase? StringComparison.Ordinal: StringComparison.OrdinalIgnoreCase; if ((bool)_dlg.SearchUp)// Ищем вверх { indexStart = txtBox1.SelectionStart - 1; indexFind = txtBox1.Text.LastIndexOf(_findString, indexStart, strComp); } else // Ищем вниз { indexStart = txtBox1.SelectionStart + txtBox1.SelectionLength; indexFind = txtBox1.Text.IndexOf(_findString, indexStart, strComp); } // Анализируем и принимаем решение if (indexFind!= -1) { txtBox1.Select(indexFind, _findString.Length);// Выделяем найденное txtBox1.Focus(); return true; } else { MessageBox.Show("Текст \"" + _findString + "\" не найден!", this.Title, MessageBoxButton.OK, MessageBoxImage.Information); txtBox1.Focus(); return false; } } private void ReplaceExec() { // Извлекаем тексты поиска и замены _findString = _dlg.FindWhat; _replaceString = _dlg.ReplaceWith; // Учет регистра при поиске, однострочный условный оператор StringComparison strComp = (bool)_dlg.MatchCase? StringComparison.Ordinal: StringComparison.OrdinalIgnoreCase; if (_findString.Equals(txtBox1.SelectedText, strComp)) txtBox1.SelectedText = _replaceString; FindNextExec(); } }}

Привязать к владельцу диалоговое окно нужно раньше, чем оно будет нарисовано, иначе заданная опция центрирования относительно владельца действовать не будет!

  • Код получился (на мой взгляд!) интересным и поучительным - попробуйте разобраться в нем

Для разнообразия, чтобы не придумывать новые имена обработчикам, которые все равно как методы нигде далее сами вызывать не будем (кроме как автоматически через события), мы применили синтаксис анонимных обработчиков. Тот код, который нам придется вызывать не только через события диалогового окна, но и через интерфейсные элементы основного окна Window1, упакован в отдельные функции.

Обратите внимание, что при объявлении ссылки на экземпляр окна мы применили модификатор доступности internal (внутренний). Этот оператор обычно используется для типов (а не членов типа), видимость которых нужно ограничить только текущей сборкой. В нашем случае это ни на что не влияет и его можно убрать или заменить на private, но интересно отметить вот что...

  • Откройте панель Class View в разделе View оболочки и посмотрите на пиктограммы членов класса Window1, который мы как раз сейчас и расширяем

Оказывается, что те члены-поля класса, которые мы применили как элементы в разметке, считаются с видимостью internal (конверт на пиктограмме). А все члены класса, которые мы объявили в процедурном коде без указания модификатора видимости (доступности), считаются закрытыми (замок на пиктограмме). Ну это так, к слову, и на наше приложение никак не влияет.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: