+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 91.78 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

WPF: Нестандартное окно

15.11.2012 16:35
DeeKey

На днях, после долгого перерыва, надо было поработать на WPF, и возникло желание заменить поднадоевший стандартный вид окон Windows 7 на что-нибудь более вдохновляющее, скажем в стиле Visual Studio 2012:

Переходить на Windows 8 ради этого еще не хотелось, как и добавлять в проекты ссылки на метро-подобные библиотеки* и разбираться с ними - это будет следуюшим шагом. А пока было интересно потратить вечер и добиться такого результата с минимальными изменениями рабочего кода. Забегая вперед, скажу что результат, как и планировалось, получился довольно чистым: фрагмент следующего кода, если не считать нескольких аттрибутов пропущенных для наглядности, это и есть окно с первого скриншота. Все изменения ограничились заданием стиля.

<Window ... Style="{StaticResource VS2012WindowStyle}">
    <DockPanel>
        <StatusBar>
            <TextBlock>Ready</TextBlock>
            <StatusBarItem HorizontalAlignment="Right">
                <ResizeGrip />
            </StatusBarItem>
        </StatusBar>
        <TextBox Text="Hello, world!" />
    </DockPanel>
</Window>

Дальше я остановлюсь на ключевых моментах и подводных камнях при создания стиля окна. Демонстрационный проект доступен на github'е, если вы захотите поразбираться с исходниками самостоятельно или же просто использовать этот стиль не вдаваясь в подробности.

Основная проблема

WPF не работает с NC-area.  NC, она же "Non-client area", она же "не-клиентская часть", она же хром, обрабатывается на более низком уровне. Если вам захотелось изменить какой-то из элементов окна - бордюр, иконку, заголовок или кнопку, то первый совет, который попадается при поиске - это убрать стиль окна и переделать все самому. Целиком.

<Window
    AllowsTransparency="true"
    WindowStyle="None"> ...

За всю историю развития WPF в этом отношении мало что изменилось. К счастью, у меня были исходники из старинного поста Алекса Яхнина по стилизации под Офис 2007, которые он писал работая над демо проектом по популяризации WPF для Микрософта, так что с нуля начинать мне не грозило.

В итоге нам надо получить один стиль, и по возможности, без дополнительных контролов: в дереве проекта XAML и код стиля расположились в директории CustomizedWindow, а основное окно в корне проекта.

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

Создаем стиль

Стиль для окна, как и для любого другого контрола в WPF задается при помощи ControlTemplate. Содержимое окна будет показываться ContentPresenter'ом, а функциональность которую проще сделать в коде c#, подключится через x:Class атрибут в ResourceDictionary. Все очень стандартно для XAML'а.

<ResourceDictionary
    x:Class="Whush.Demo.Styles.CustomizedWindow.VS2012WindowStyle">
    <Style x:Key="VS2012WindowStyle" TargetType="{x:Type Window}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <!-- XAML хрома окна с отрисовкой бордюра, иконки и кнопок -->
                    <ContentPresenter />
                    <!-- еще XAML хрома окна -->
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Сразу же определим кнопки управления окном в стиле Студии 2012. Это будет единственный дополнительный глобальный стиль на случай если потом возникнет желание использовать такие кнопки в приложении.

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

XAML стиля кнопки

Изображения на кнопках проще всего сделать "в векторе". Например, вот так выглядит maximize:

<Path StrokeThickness="1"
    RenderOptions.EdgeMode="Aliased"
    Data="M0,0 H8 V8 H0 V0 M0,1 H8 M0,2 H8" />

Для текста заголовка используем стандартный шрифт Segoe UI. Единственная особенность здесь - убедиться, что текст отрисован без размытия, иначе заголовок окна будет выглядеть… плохо он будет выглядеть - как во второй строчке на скриншоте.

Кстати, для Path'а на кнопках с той же целью использовался EdgeMode="Aliased", а
для текста в WPF 4+ появилась долгожданная возможность указать, что отображаться он будет на дисплее, а не на "идеальном устройстве", что и позволило добиться приемлимой четкости на наших неидеальных экранах.

<TextBlock
    TextOptions.TextRenderingMode="ClearType"
    TextOptions.TextFormattingMode="Display" > ...

Еще одна интересная особенность связана с "геометрией Windows 7" при распахивании окна на весь экран. Windows жульничает, масштабируя окно так, что бордюр целиком уходит за границу экрана, оставляя на мониторе только клиентскую часть окна. Естественно, что Windows при этом больше не отрисовывает бордюр и для стандартных окон все работает как ожидалось. WPF это никак не отрабатывает и, для таких окон как у нас, есть риск потерять часть изображения или начать рисовать на соседнем мониторе, если он подключен.

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

Оживляем окно

Помимо реакции на кнопки и иконку, окно должно перемещаться и изменять размер при drag'е за заголовок, за края и уголки. Соответствующие горячие зоны проще всего задать при помощи невидимых контролов. Пример для левого верхнего (северо-западного) угла.

<Rectangle
    x:Name="rectSizeNorthWest"
    MouseDown="OnSizeNorthWest"
    Cursor="SizeNWSE" Fill="Transparent"
    VerticalAlignment="Top" HorizontalAlignment="Left"
    Width="5" Height="5" />

При наличие атрибута Class в ресурсах, методы этого класса можно вызывать просто по имени как обычные обработчики событий, чем мы и воспользовались. Сами обработчики, например MinButtonClick и OnSizeNorthWest, выглядят примерно так:

void MinButtonClick(object sender, RoutedEventArgs e) {
    Window window = ((FrameworkElement)sender).TemplatedParent as Window;
    if (window != null) window.WindowState = WindowState.Minimized;
}

void OnSizeNorthWest(object sender) {
    if (Mouse.LeftButton == MouseButtonState.Pressed) {
        Window window = ((FrameworkElement)sender).TemplatedParent as Window;
        if (window != null && window.WindowState == WindowState.Normal) {
            DragSize(w.GetWindowHandle(), SizingAction.NorthWest);
        }
    }
}

DragSize далее вызывает WinAPI (исходник) и заставляет Windows перейти в режим измененения размера окна как в до-дотнетовские времена.

Почти готово. Зададим триггеры для контроля изменений интерфейса при изменении состояния окна. Вернемся в XAML и, например, заставим StatusBar'ы изменять цвет в зависимости от значения Window.IsActive.

XAML для StatusBar'а

Обратите внимание, что этот стиль влияет не на темплэйт окна, а на контролы помещенные в наше окно. Помните самый первый фрагмент с пользовательским кодом?

<Window ... Style="{StaticResource VS2012WindowStyle}">
    ...
    <StatusBarItem HorizontalAlignment="Right">
    ...
</Window>

Вот стиль именно этого StatusBar'а мы сейчас и задали. При желании и времени так же можно задать и стиль для других классов контролов, например подправить ScrollBar, чтобы он тоже соответствовал нужному стилю. Но это уже будет упражнение на следующий свободный вечер.

Собираем все вместе

Все. Нам осталось только подключить стиль к проекту через ресурсы приложения:

<Application ... StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Styles/CustomizedWindow/VS2012WindowStyle.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

И можно использовать его в любом окне.
 

- Д.

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

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

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года