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

События и команды в WPF

Подключение функциональности Find and Replace к источникам задач

Теперь нам осталась самая малость - подключить готовый код функциональности Find and Replace к обработчикам интерфейсных элементов в основном окне и испытать его работу. Заготовки обработчиков мы создавали ранее и они находятся в файле Edit.cs.

  • Добавьте в соответствующие обработчики файла Edit.cs следующий код
private void FindOnExecute(object sender, RoutedEventArgs e)
        {
            CreateDialog();
        }
    
        private void FindNextOnExecute(object sender, RoutedEventArgs e)
        {
            if (_dlg == null)
                CreateDialog();
            else
                FindNextExec();
        }
    
        private void ReplaceOnExecute(object sender, RoutedEventArgs e)
        {
            if (_dlg == null)
            {
                CreateDialog();
                _dlg.ShowReplace = true;
            }
            else if (_dlg.ShowReplace == false)
                _dlg.ShowReplace = true;
            else
                ReplaceExec();
        }
    
        private void GoToOnExecute(object sender, RoutedEventArgs e)
        {
        }
  • Запустите проект Notepad1 и испытайте функциональность Find and Replace. Разберитесь с кодом

Начальный интерфейс диалогового окна для задачи Replace будет таким


Когда диалоговое окно Find and Replace создано, оно размещается поверх своего родителя. Кнопки диалогового окна возбуждают события, которые обрабатываются кодом основного окна, содержащего текст. Тот же самый код может вызываться и в обработчиках основного окна, если пользователь управляет через интерфейсные элементы основного окна. Этот подход чем-то напоминает автомобиль с дублирующими педалями.

На панели инструментов осталось незадействованным текстовое поле поиска, обозначенное в разметке как

<ToolBar Header="Find:">
                <TextBox Width="100" />
                <Button Name="btnFind" Click="FindOnExecute" Width="23" Content="{StaticResource iconFind}" />
            </ToolBar>

Я оставил его в покое (надоело), попробуйте сами, если хотите, использовать его в коде, но для этого прежде всего ему нужно присвоить имя, например, txtFind. Ну а лучше - пусть болтается для солидности.

Следующим шагом реализуем последнюю задачу раздела Edit в меню нашего приложения - Go To... Как видно из запланированного (опрометчиво) нами многоточия после названия задачи, это будет опять связано с разработкой диалогового окна. Причем, это окно должно быть модальным, потому что выполняет одноразовую задачу.

Разработка диалогового окна Go To

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

>

  • Заполните файл GoToDialog.xaml следующей разметкой
<Window x:Class="Notepad1.GoToDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    SizeToContent="WidthAndHeight"
    WindowStartupLocation="CenterOwner"
    ShowInTaskbar="false"
    Title="Go To Line"
    ResizeMode="NoResize"
    Activated="OnActivated"
    >
    <StackPanel 
        Background="{StaticResource DialogBackgroundBrush}"
        >
        <StackPanel
            Orientation="Vertical"
            Margin="5"            
            >
            <Label
                Name="_rangeNumber"
                Margin="0 0 8 3"
                VerticalAlignment="Bottom"
                Content="_Line number" />
            <TextBox
                Name="_lineNumberTextBox"
                TabIndex="0"
                MinWidth="220"
                Margin="5,0" />
        </StackPanel>
    
        <StackPanel
            Orientation="Horizontal"
            Margin="5,0,5,5" HorizontalAlignment="Right">
            <Button
                Click="OkClicked"
                IsDefault="true"
                MinWidth="75"
                MinHeight="23"
                Content="OK" />
            <Button
                Click="CancelClicked"
                IsCancel="true"
                Margin="15 0 5 0"
                MinWidth="75"
                MinHeight="23"
                Content="Cancel" />
        </StackPanel>
    </StackPanel>
</Window>

Представление окна в графическом конструкторе по данной разметке будет таким


Обратите внимание, что для кнопки OK свойство IsDefault="true", чтобы пользователь мог закрыть окно клавишей Enter, а для второй кнопки IsCancel=true - чтобы выйти по клавише Esc.

  • Пройдитесь по разметке и командой Navigate to Event Handler контекстного меню для записей событий создайте заготовки обработчиков в файле процедурного кода GoToDialog.xaml.cs

Применение вложенных ресурсов

Для тренировки воспользуемся способом хранения и извлечения некоторых сообщений в ресурсах сборки.

  • В панели Solution Explorer вызовите контекстное меню для узла проекта и добавьте командой Add/New Item текстовый файл с любым именем (оставьте по умолчанию)

>

  • В панели Solution Explorer вызовите контекстное меню на созданном текстовом файле и командой Rename присвойте ему новое имя StringTable.ru-ru.resText

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

  • В панели Solution Explorer выделите файл StringTable.ru-ru.resText и в панели Properties установите для него следующие директивы:


  • Заполните файл StringTable.ru-ru.resText следующими парами ключ=значение
GotoErrorDialogTitle=Go To Line Error
GotoErrorMsgFormat=Текстовое поле должно\nсодержать целое число
GotoErrorMsgEmpty=Введите число в текстовое поле
GotoErrorMsgRange=Выход за границы диапазона
  • Заполните файл GoToDialog.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;
    
// Дополнительные подключения пространств имен
using System.Resources;
using System.Reflection;
    
namespace Notepad1
{
    public partial class GoToDialog : Window
    {
        public GoToDialog()
        {
            InitializeComponent();
    
            // Сохраняем первое значение Label
            _rangeOrigin = _rangeNumber.Content.ToString();
        }
    
        // Объявляем событие для прослушивания в основном окне
        public event EventHandler GotoActivate;
    
        // Закрытые поля класса
        int _lineNumber = 0;
        int _maxLineNumber;
        ResourceManager res =
            new ResourceManager("Notepad1.StringTable", 
                Assembly.GetExecutingAssembly());
        String _rangeOrigin;
    
        // Свойства доступа
        public int LineNumber
        {
            get { return _lineNumber; }
            set
            {
                _lineNumber = value;
                _lineNumberTextBox.Text = _lineNumber.ToString();
            }
        }
        public int MaxLineNumber
        {
            get { return _maxLineNumber; }
            set { _maxLineNumber = value; }
        }
    
        private void OnActivated(object sender, EventArgs e)
        {
            // Если существуют обработчики, инициируем событие
            if (GotoActivate != null)
                GotoActivate(this, EventArgs.Empty);
    
            _rangeNumber.Content = _rangeOrigin +
                String.Format(" (1 - {0}):", _maxLineNumber);
            _lineNumberTextBox.Focus();
            _lineNumberTextBox.SelectAll();// Выделяем содержимое
        }
    
        private void OkClicked(object sender, RoutedEventArgs e)
        {
            // Не закрывать диалог, пока есть ошибки
            if (string.IsNullOrEmpty(_lineNumberTextBox.Text))
            {
                MessageBox.Show(res.GetString("GotoErrorMsgEmpty"), 
                    res.GetString("GotoErrorDialogTitle"));
                return;
            }
            if (!int.TryParse(_lineNumberTextBox.Text, out _lineNumber))
            {
                MessageBox.Show(res.GetString("GotoErrorMsgFormat"), 
                    res.GetString("GotoErrorDialogTitle"));
                return;
            }
            if (LineNumber > _maxLineNumber || LineNumber <= 0)
            {
                MessageBox.Show(res.GetString("GotoErrorMsgRange"), 
                    res.GetString("GotoErrorDialogTitle"));
                return;
            }
    
            this.DialogResult = true;
            this.Close();
        }
    
        private void CancelClicked(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
            this.Close();
        }
    }
}

Обратите внимание на то, как мы в коде извлекаем ресурсы, вложенные (Embedded) ранее в текстовый файл StringTable.ru-ru.resText.

Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?

Dmitriy Ivanchenko
Dmitriy Ivanchenko
Украина, Кировоград, Виктория-П, 2011
Татьяна Ковалюк
Татьяна Ковалюк
Украина, Киев, Киевский политехнический институт, 1974