| исключение в лабораторной работе № 3 |
Графика в 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);
}
}


