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

Графика в WPF

Упражнение 2. Имитация полноэкранного режима с отключением системных клавиш

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

window.WindowStyle = WindowStyle.None;
window.ResizeMode = ResizeMode.NoResize;

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

Есть более сложный способ, приведенный в "http://www.swart.ws/2009/03/kiosk-full-screen-wpf-applications.html", но он имеет те же недостатки.

Для достижения полной иллюзии режима FullScreen следует отключить системные клавиши, вызывающие панель задач и меню Пуск, и самый эффективный (на мой взгляд) способ приведен в "http://www.sql.ru/Forum/actualthread.aspx?tid=632552", которым мы и воспользуемся в данном упражнении.

Из приведенного в статье http://support.microsoft.com/kb/126449/ru сочетания клавиш мы воспользуемся только следующими вариантами:

  • CTRL + ESC: открытие меню Пуск.
  • Клавиша WIN: открытие меню Пуск.
  • ALT + ESC: показать панель задач и переключать развернутые окна.
  • ALT + TAB: переключение между программами.

Этого будет достаточно, чтобы поддерживать полноэкранный режим и одновременно не блокировать остальную функциональность клавиатуры.

  • Добавьте к решению командой File/Add/New Project новый проект с именем FullScreen и назначьте его стартовым

  • В панели Solution Explorer добавьте к корню проекта FullScreen новую папку Images командой контекстного меню Add/New Folder
  • В панели Solution Explorer командой Add/Existing Item контекстного меню для папки Images скопируйте в нее файл flower2.jpg из прилагаемого каталога Source
  • Определите в интерфейсной части окна следующий код
<Window x:Class="FullScreen.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    Background="Green"
    Loaded="Window_Loaded"
    KeyDown="Window_KeyDown"
    KeyUp="Window_KeyDown"
        >
    <Window.ContextMenu>
        <ContextMenu>
            <MenuItem Name="changeScreen" Click="MenuItem_Click" />
        </ContextMenu>
    </Window.ContextMenu>
    <DockPanel>
        <Menu Name="menu" DockPanel.Dock="Top">
            <MenuItem Header="File">
                <MenuItem Header="Open" />
                <MenuItem Header="Save" />
                <MenuItem Header="SaveAs" />
                <MenuItem Header="Exit" />
            </MenuItem>
            <MenuItem Header="Edit">
                <MenuItem Header="Cut" />
                <MenuItem Header="Copy" />
                <MenuItem Header="Paste" />
            </MenuItem>
        </Menu>
        <Image Source="Images/flower2.jpg" Stretch="Uniform" /> 
    </DockPanel>
</Window>

Для настройки окна и его элементов мы применили синтаксис атрибута, а для создания каркаса контекстного меню - синтаксис тега свойства ( свойства зависимости, присоединенные свойства ). Атрибут Stretch элемента Image может принимать следующие значения:

  • None - изображение масштабируется до естественного размера и в области просмотра справа внизу видно столько, сколько поместилось
  • Fill - изображение масштабируется по всей области просмотра без соблюдения пропорций
  • Uniform - изображение масштабируется с соблюдением пропорций, чтобы полностью поместиться в область просмотра
  • UniformToFill - изображение масштабируется с соблюдением пропорций так, чтобы в область просмотра полностью вместился хотя бы один размер, а для другой стороны видно столько, сколько поместилось

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

  • Найдите в разметке файла Window1.xaml атрибуты событий
    • Loaded="Window_Loaded"
    • KeyDown="Window_KeyDown"
    • KeyUp="Window_KeyDown"
    • Click="MenuItem_Click"
  • В любом месте каждого из этих атрибутов щелкните правой кнопкой мыши и выполните команду Navigate to Event Handler.


Оболочка создаст обработчики с указанными именами, а если обработчик уже существует, то перейдет к нему.

  • Заполните файл поддержки разметки Window1.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.Navigation;
using System.Windows.Shapes;
    
namespace FullScreen
{
    public partial class Window1 : Window
    {
        // Объявляем как поля для видимости в функциях
        bool fullScreen = false;// Состояние экрана
        WindowStyle windowStyle;
        WindowState windowState;
        ResizeMode resizeMode;
    
        public Window1()
        {
            InitializeComponent();
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Запоминаем начальные параметры окна
            windowState = this.WindowState;
            windowStyle = this.WindowStyle;
            resizeMode = System.Windows.ResizeMode.CanResizeWithGrip;
            this.ResizeMode = resizeMode;
            changeScreen.Header = "FullScreen";
        }
    
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            FullScreen();
        }
    
        private void FullScreen()
        {
            if (!fullScreen)// Переходим в полноэкранный режим 
            {
                if (this.WindowState == WindowState.Maximized)
                {
                    // Чтобы скрыть панель задач и не было мерцания
                    this.Hide();
                    this.WindowState = WindowState.Normal;
                }
    
                App.Current.MainWindow.WindowStyle = WindowStyle.None;// Без заголовка
                App.Current.MainWindow.Topmost = true;      // На передний план
                App.Current.MainWindow.WindowState = WindowState.Maximized;// Развернуть
                App.Current.MainWindow.ResizeMode = ResizeMode.NoResize;// Неизменяемое
    
                menu.Visibility = Visibility.Collapsed;// Скрываем меню
                HookSystemKeys.FunHook();// Запрещаем системные клавиши
                this.Visibility = Visibility.Visible;
    
                fullScreen = true;
                changeScreen.Header = "WindowScreen";
            }
            else // Восстанавливаем оконный режим
            {
                this.WindowStyle = windowStyle;
                this.Topmost = false;
                this.WindowState = windowState;
                this.ResizeMode = resizeMode;
    
                menu.Visibility = Visibility.Visible;// Показываем меню
                HookSystemKeys.FunUnHook();// Освобождаем системные клавиши
    
                fullScreen = false;
                changeScreen.Header = "FullScreen";
            }
        }
    
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
                this.Close();
        }
    }
}

В приведенном коде используется класс HookSystemKeys, который нам нужно подключить к приложению и который взят из "http://www.sql.ru/Forum/actualthread.aspx?tid=632552" (там же и описан).

  • Добавьте к текущему проекту FullScreen командой Project/Add New Item новый файл с именем HookSystemKeys.cs

  • Заполните файл HookSystemKeys.cs так
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
    
// Для перечисления Keys 
using System.Windows.Forms; 
    
namespace FullScreen
{
    // Отключение системной клавиши
    // http://www.sql.ru/Forum/actualthread.aspx?tid=632552
    class HookSystemKeys
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYUP = 257;// Отпускание любой клавиши
    
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
    
        // Поддержка флагов состояния системных клавиш 
        static bool CtrlKey, AltKey, WinKey;
        private static void StateKey(int vkCode, IntPtr wParam)
        {
            switch ((Keys)vkCode)
            {
                case Keys.LControlKey:
                case Keys.RControlKey:
                    if (wParam == (IntPtr)WM_KEYUP)
                        CtrlKey = false;
                    else
                        CtrlKey = true;
                    break;
                case Keys.LMenu:
                case Keys.RMenu:
                    if (wParam == (IntPtr)WM_KEYUP)
                        AltKey = false;
                    else
                        AltKey = true;
                    break;
                case Keys.LWin:
                case Keys.RWin:
                    if (wParam == (IntPtr)WM_KEYUP)
                        WinKey = false;
                    else
                        WinKey = true;
                    break;
            }
        }
    
        // Общедоступная упаковка оригинала
        public static void FunHook()
        {
            _hookID = SetHook(_proc);
        }
        public static void FunUnHook()
        {
            UnhookWindowsHookEx(_hookID);
        }
    
        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, 
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }
    
        private delegate IntPtr LowLevelKeyboardProc(int nCode, 
            IntPtr wParam, IntPtr lParam);
    
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            int vkCode = Marshal.ReadInt32(lParam);
            StateKey(vkCode, wParam);
            if (WinKey                                      // Системная
                || CtrlKey && (Keys)vkCode == Keys.Escape   // Ctrl+Esc
                || AltKey && (Keys)vkCode == Keys.Escape    // Alt+Esc
                || AltKey && (Keys)vkCode == Keys.Tab)      // Alt+Tab
            {
                return (IntPtr)1;
            }
            else
                return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
    
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
    
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, 
            IntPtr wParam, IntPtr lParam);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
    }
}
Алексей Бабушкин
Алексей Бабушкин

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

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