Опубликован: 05.08.2010 | Доступ: свободный | Студентов: 2008 / 45 | Оценка: 4.50 / 4.40 | Длительность: 60:26:00
Самостоятельная работа 12:

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

Подключение функциональности Go To к основному окну

  • Подключите диалоговое окно Go To к обработчику главного окна в файле Edit.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
    {
        //------------------------------------------------------
        //
        //  Обработчики источников задач 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)
        {
            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();
        }
    
        #region Задача Go To
        private void GoToOnExecute(object sender, RoutedEventArgs e)
        {
            GoToDialog dlg = new GoToDialog();
            dlg.Owner = this;
            dlg.LineNumber = CaretLineNumber;
            /***** Врет для завернутых строк Word Wrap! ******************
            dlg.MaxLineNumber = txtBox1.LineCount; 
            /*************************************************************/
            dlg.MaxLineNumber = GetMaxNumber();
    
            // Параметры анонимного обработчика "от фонаря", 
            // все равно не используем
            dlg.GotoActivate += delegate(object sender2, EventArgs e2)
            {
                // Заполняем текстовое поле диалога текущей строкой
                dlg.LineNumber = CaretLineNumber;
            };
    
            // Запускаем в модальном режиме. Ждет и закрывается
            if (dlg.ShowDialog() == true)
            {
                // Устанавливаем каретку (курсор) в начало строки
                CaretLineNumber = dlg.LineNumber;
            }
    
            txtBox1.Focus();
        }
    
        int GetMaxNumber()
        {
            int count = 0;
            int pos = 0;
            int caretPos = txtBox1.Text.Length + 1;
            while (pos < caretPos)
            {
                count++;        // Счетчик строк
                pos = txtBox1.Text.IndexOf("\r\n", pos);
                if (pos != -1)  // Нашли очередную пару
                    pos += 2;   // Сдвигаемся правее найденных
                else
                    break;// Больше нет
            }
            return count;
        }
    
        int CaretLineNumber
        {
            get
            {
                /***** Врет для завернутых строк Word Wrap! ******************
                int caretPos = txtBox1.SelectionStart;
                return (txtBox1.GetLineIndexFromCharacterIndex(caretPos) + 1);
                /*************************************************************/
    
                int count = 0;
                int pos = 0;
                int caretPos = txtBox1.SelectionStart + 1; //txtBox1.CaretIndex
                while (pos < caretPos)
                {
                    count++;        // Счетчик строк
                    pos = txtBox1.Text.IndexOf("\r\n", pos);// \n - перевод строки
                    if (pos != -1)  // Нашли очередную пару
                        pos += 2;   // Сдвигаемся правее найденных
                    else
                        break;// Больше нет
                }
                return count;
            }
            set
            {
                value = value - 1;
                int count = 0;
                int pos = 0;
                while (count < value)   // Пока не превышает заданную
                {
                    pos = txtBox1.Text.IndexOf("\r\n", pos);// \r - возврат каретки
                    if (pos != -1)  // Нашли очередную пару
                    {
                        count++;    // Счетчик строк
                        pos += 2;   // Сдвигаемся правее найденных
                    }
                    else
                    {
                        pos = txtBox1.Text.Length;
                        break;
                    }
                }
                // Позиционируем курсор
                txtBox1.SelectionStart = pos;
                txtBox1.SelectionLength = 0;
            }
        }
        #endregion Задача Go To
    
        private void SelectAllOnExecute(object sender, RoutedEventArgs e)
        {
            txtBox1.SelectAll();
        }
    }
}
  • Запустите проект и испытайте введенную функциональность Go To. Разберитесь с кодом

Прочие задачи

В нашем приложении остались еще три запланированные задачи, обработчики которых мы разместили в файле Other.cs. Задачи Font и About требуют создания диалоговых окон. Чтобы не усложнять себе жизнь и не отвлекаться, ограничимся только простым показом стандартных диалогов.

  • Заполните обработчики в файле Other.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
    {
        //------------------------------------------------------
        //
        //  Прочие обработчики
        //
        //------------------------------------------------------
    
        private void FontOnExecute(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FontDialog dlg = 
                new System.Windows.Forms.FontDialog();
            switch (dlg.ShowDialog())
            {
                case System.Windows.Forms.DialogResult.Abort:
                case System.Windows.Forms.DialogResult.Cancel:
                case System.Windows.Forms.DialogResult.Ignore:
                case System.Windows.Forms.DialogResult.No:
                case System.Windows.Forms.DialogResult.None:
                case System.Windows.Forms.DialogResult.OK:
                case System.Windows.Forms.DialogResult.Retry:
                case System.Windows.Forms.DialogResult.Yes:
                    break;
            }
        }
    
        private void WordWrapOnExecute(object sender, RoutedEventArgs e)
        {
            if (itemWordWrap.IsChecked)
                txtBox1.TextWrapping = TextWrapping.Wrap;
            else
                txtBox1.TextWrapping = TextWrapping.NoWrap;
        }
    
        private void AboutOnExecute(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Сведения об авторах...\n" + 
                "Сведения о программе...", "About");
        }
    }
}
  • Запустите проект и проверьте добавленную функциональность

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

  • Добавьте в разметку открывающего дескриптора элемента txtBox1 в файле Window1.xaml следующий атрибут
<!-- Многострочное текстовое поле редактирования -->
        <TextBox TextWrapping="Wrap"
                 AcceptsReturn="True" 
                 AcceptsTab="True"
                 VerticalScrollBarVisibility="Auto"
                 Name="txtBox1"
                 TextChanged="txtBox1_TextChanged" 
                 HorizontalScrollBarVisibility="Auto"
                 >
  • Запустите проект и проверьте добавленную функциональность

Принудительная перерисовка окна

Если внимательно посмотреть на работающее приложение, то можно заметить один неприятный нюанс. Когда по щелчку мыши вызываются диалоговые окна и они перекрывают элементы меню или кнопки, то после закрытия диалогов интерфейсные элементы не перерисовываются. Это происходит потому, что элементы теряют фокус за счет переключения на другое окно и мышь уходит (leave) с них не по установленной схеме. Как заставить окно WPF перерисоваться (paint), я так и не нашел (пока), поэтому ничего не оставалось, как применить следующий 'убогий' способ...

  • В файле Window1.xaml добавьте в открывающий дескриптор окна подписку на событие Activated
<Window x:Class="Notepad1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        
    Title="Window1: Управление состоянием источников команд"
    Width="500" Height="375"
    MinWidth="500" MinHeight="375"
    WindowStartupLocation="CenterScreen"
    ResizeMode="CanResizeWithGrip"
    Loaded="Window_Loaded"
    Icon="Notepad.ico"
    Closing="Window_Closing"
    Activated="Window_Activated"
        >
    .........................................
</Window>
  • Создайте обработчик Window_Activated() в файле Window1.xaml .cs и заполните его так
private void Window_Activated(object sender, EventArgs e)
        {
            this.Height = this.ActualHeight - 1;
            this.Height = this.ActualHeight + 1;
            this.txtBox1.Focus();
        }
  • Испытайте приложение - окно снизу немного дергается, но возможно пользователь этого не заметит (кто сейчас смотрит под ноги!), зато интерфейсные элементы "не залипают"
Алексей Бабушкин
Алексей Бабушкин

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

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