Опрос
Вы участвуете в программе Windows Insider?
Популярные новости
Обсуждаемые новости

19.07.2006 04:02 | Raiker

Avalon содержмт множество средств оформления. Одними из таких средств являются растровые эффекты (Bitmap Effects). Они применимы практически к любому элементу WPF и позволяют легко и быстро создавать свечение, размытие, выдавливание и другие эффекты. Если применить фантазию, можно приспособить эти эффекты для создания чего-то менее тривиального - например окна в стиле Windows Vista. Этим мы и займемся сегодня.

Создайте новый проект типа WinFX Windows Application и назовите его "MyVistaStyle".
Зададим свойства для формы, чтобы сделать ее прозрачной прямо в XAML-коде:

WindowStyle ="None" AllowsTransparency="True" Background ="Transparent"


Далее разместим на форме прямоугольник - он и будет отвечать за внешний вид нашего окна:

<Rectangle HorizontalAlignment ="Stretch" VerticalAlignment ="Stretch"
                 Opacity ="0.9"
                 Stroke ="Gray"  Fill ="WhiteSmoke"
                 StrokeThickness ="1"
                 RadiusX ="5" RadiusY ="5"/>


Увеличьте значения свойств Width и Height нашего окна Height="480" Width="640". Теперь давайте создадим загаловок окна. Для этого будем использовать хорошо знакомый вам по обычному программированию для .NET 2.0 - Label. Привожу полный код для сверки:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MyVistaStyle" Height="480" Width="640"
    WindowStyle ="None" AllowsTransparency="True" Background ="Transparent"
    >
    <Grid>
      <Rectangle HorizontalAlignment ="Stretch" VerticalAlignment ="Stretch"
                 Opacity ="0.9"
                 Stroke ="Gray"  Fill ="WhiteSmoke"
                 StrokeThickness ="1"
                 RadiusX ="5" RadiusY ="5" />

      <Label FontFamily ="SgoeUI" FontSize ="15" Foreground ="Black"
             Content ="Мое приложение в стиле Vista"
             HorizontalAlignment ="Stretch" VerticalAlignment ="Top"
             Margin ="10,10,0,0"
             Name="MyCaptionLabel" />
    </Grid>
</Window>

ndow>[/code]
Давайте посмотрим на результат:



Обратите внимание, что я задал для элемента Label имя MyCaptionLabel - я сделал это, чтобы дать возможность пользователю перетаскивать окно не за любою точку, а только за заголовок. Для этого добавьте обработчик события MouseLeftButtonDown для нашей надписи MyCaptionLabel и внесите в его тело код: Me.DragMove()

Запустите проект и убедитесь, окно теперь легко перемещается за заголовок. Теперь давайте займемся кнопками сворачивания, разворачивания и закрытия окна. Вы можете подготовить сами их изобржение в формате png, однако для того, чтобы вы легко выполнили задание этой статьи, я разместил небольшой архив с нужными изображениями тут.

Скачайте его и добавьте все содержащиеся в архиве изображения к ресурсам проекта (если вы затрудняетесь - прочтите статью № 006 ). Теперь давайте разместим их на форме:

[code]<Image Source ="btnClose.png" Width ="44" Margin ="0,2,2,0"
HorizontalAlignment ="Right" VerticalAlignment ="Top"/>

<Image Source ="btnMaximize.png" Width ="26" Margin ="0,2,46,0"
HorizontalAlignment ="Right" VerticalAlignment ="Top"/>

<Image Source ="btnMinimize.png" Width ="26" Margin ="0,2,72,0"
HorizontalAlignment ="Right" VerticalAlignment ="Top"/>[/code]
Посмотрите на результат:



Теперь придадим кнопкам функциональность. Для этого задайте им следующие имена: для первой Name="myBtnClose" для второй Name="myBtnMax" и для третьей Name="myBtnMin". Перекомпилируйте проект и задайте для всех трех элементов обработчики уже давно знакомого события MouseLeftButtonDown. Давайте теперь внесем код (примеры на VB):

[code]Для первой: Me.Close()
Для второй:
If Me.WindowState = Windows.WindowState.Maximized Then
Me.WindowState = Windows.WindowState.Normal
Else
Me.WindowState = Windows.WindowState.Maximized
End If
Для третьей: Me.WindowState = Windows.WindowState.Minimized[/code]
Запустите проект и убедитесь, что кнопки выполняют нужные функции.

Теперь давайте займемся оформлением уже подготовленных элементов! Сделаем наши кнопки похожими на кнопки окон Windows Vista. Для этого применим растровые эффекты. Добавьте такой код к определению изображения MyBtnClose:

[code]<Image Source ="btnClose.png" Width ="44" Margin ="0,2,2,0"
HorizontalAlignment ="Right" VerticalAlignment ="Top"
Name="myBtnClose">

<Image.BitmapEffect>
<OuterGlowBitmapEffect x:Name="myOuterGlowBitMapEffect"
GlowColor="Red" GlowSize="0" Noise="0"
Opacity="0.5" />
</Image.BitmapEffect>

<Image.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect"
Storyboard.TargetProperty="GlowSize"
To="8" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect"
Storyboard.TargetProperty="GlowSize"
To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>[/code]
Давайте разберемся, что и как тут работает. Прежде всего секция <Image.BitmapEffect> открывает доступ к различным растровым эффектам. Мы применим эффект внутреннего свечения при помощи определителя <OuterGlowBitmapEffect>. Именно этот эффект сделает нашу кнопку похожей на кнопку из Vista. Для того, чтобы кнопка "светилась изнутри" при наведении мыши и затухала, когда мышь покидает область кнопки, мы используем анимацию. Здесь все как обычно - свойство Triggers и две доски <Storyboard> - одна для события MouseEnter а другая для MouseLeave. Подробно объяснять не буду, так как мы рассматривали подобные анимации уже неоднократно. Скажу лишь, что анимации мы подвергаем свойство GlowSize нашего BitmapEffect-а.

Добавьте практически тотже самый код для двух других кнопок. Измените лишь свойство GlowColor на DodgerBlue для эффектов свечения, так как наши оставшиеся кнопки должны светиться не красным, а голубым цветом. Также не забудьте изменить имя для второго и третьего OuterGlowBitmapEffect с myOuterGlowBitMapEffect на какие-нибудь другие, чтобы не вызвать конфликта имен и подредактируйте ссылающиеся на них свойста TargetName. Думаю, вы справитесь без проблем.

Запускаем и смотрим на результат:



Обратите внимание, что кнопки не только светяться, но и обеспечивают плавные переходы, при движении мышью. Есть только один недостаток - наше свечение ограничивается верхней границей окна. Это легко исправить!

Дело в том, что наш прямоугольник, формирующий внешний вид окна, плотно прилегает к форме. Немного отредактируем свойства прямоугольника, чтобы он оставил небольшую зону перед верхней границей. Новые свойства прямоугольника:

[code]Margin ="0,7,0,0"[/code]
Запускаем:



Уупс.. забыли про кнопки. Меняем свойства Margin для всех трех кнопок на такие:

[code]Для первой: Margin ="0,9,2,0"
Для второй: Margin ="0,9,46,0"
Для третьей: Margin ="0,9,72,0"[/code]
Проверяем:



Посмотрите, какого замечательного эффекта мы смогли добиться!


В завершении статьи традиционно привожу полный листинг:

VB-листинг:

[code]Partial Public Class Window1
Inherits Window

Public Sub New()
InitializeComponent()
End Sub

Private Sub MyCaptionLabel_MouseLeftButtonDown(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs)_
Handles MyCaptionLabel.MouseLeftButtonDown
Me.DragMove()
End Sub

Private Sub myBtnClose_MouseLeftButtonDown(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles myBtnClose.MouseLeftButtonDown
Me.Close()

End Sub

Private Sub myBtnMax_MouseLeftButtonDown(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles myBtnMax.MouseLeftButtonDown

If Me.WindowState = Windows.WindowState.Maximized Then
Me.WindowState = Windows.WindowState.Normal
Else
Me.WindowState = Windows.WindowState.Maximized
End If
End Sub
Private Sub myBtnMin_MouseLeftButtonDown(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles myBtnMin.MouseLeftButtonDown
Me.WindowState = Windows.WindowState.Minimized

End Sub
End Class[/code]
XAML-листинг:

[code]<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MyVistaStyle" Height="480" Width="640"
WindowStyle ="None" AllowsTransparency="True" Background ="Transparent"
>
<Grid>
<Rectangle Margin ="0,7,0,0" HorizontalAlignment ="Stretch"
VerticalAlignment ="Stretch" Opacity ="0.9"
Stroke ="Gray" Fill ="WhiteSmoke"
StrokeThickness ="1" RadiusX ="5" RadiusY ="5" />

<Label FontFamily ="SgoeUI" FontSize ="15" Foreground ="#FFFFFF"
Content ="Мое приложение в стиле Vista"
HorizontalAlignment ="Stretch" VerticalAlignment ="Top"
Margin ="10,10,0,0"
>
<Label.BitmapEffect >
<BlurBitmapEffect Radius="10" KernelType="Gaussian" />
</Label.BitmapEffect>

</Label>

<Label FontFamily ="SgoeUI" FontSize ="15" Foreground ="Black"
Content ="Мое приложение в стиле Vista"
HorizontalAlignment ="Stretch" VerticalAlignment ="Top"
Margin ="10,10,0,0"
Name="MyCaptionLabel" />

<Image Source ="btnClose.png" Width ="44" Margin ="0,9,2,0"
HorizontalAlignment ="Right" VerticalAlignment ="Top"
Name="myBtnClose">

<Image.BitmapEffect>
<OuterGlowBitmapEffect x:Name="myOuterGlowBitMapEffect"
GlowColor="Red" GlowSize="0" Noise="0"
Opacity="0.5" />
</Image.BitmapEffect>
<Image.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect"
Storyboard.TargetProperty="GlowSize"
To="8" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect"
Storyboard.TargetProperty="GlowSize"
To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>

<Image Source ="btnMaximize.png" Width ="26" Margin ="0,9,46,0"
HorizontalAlignment ="Right" VerticalAlignment ="Top"
Name="myBtnMax">

<Image.BitmapEffect>
<OuterGlowBitmapEffect x:Name="myOuterGlowBitMapEffect2"
GlowColor="DodgerBlue" GlowSize="0"
Noise="0"
Opacity="0.5" />
</Image.BitmapEffect>
<Image.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect2"
Storyboard.TargetProperty="GlowSize"
To="8" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect2"
Storyboard.TargetProperty="GlowSize"
To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>

</Image>

<Image Source ="btnMinimize.png" Width ="26" Margin ="0,9,72,0"
HorizontalAlignment ="Right" VerticalAlignment ="Top"
Name ="myBtnMin">

<Image.BitmapEffect>
<OuterGlowBitmapEffect x:Name="myOuterGlowBitMapEffect3"
GlowColor="DodgerBlue" GlowSize="0"
Noise="0"
Opacity="0.5" />
</Image.BitmapEffect>
<Image.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect3"
Storyboard.TargetProperty="GlowSize"
To="8" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="myOuterGlowBitMapEffect3"
Storyboard.TargetProperty="GlowSize"
To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>

</Image >

</Grid>
</Window>[/code]

Espoir, TheVista.ru Team
Июль, 2006

Комментарии

Не в сети

А можно совет дам ненавязчивый?

Обычно принято к статье прилагать весь код в виде законченого компилируемого и запускаемого solution...

19.07.06 17:14
0
Не в сети

А я та думал, что Espoir слишком все разжевывает )

19.07.06 17:45
0
Не в сети

ладно, предыдущий пост можно игнорировать...

19.07.06 17:50
0
Не в сети

А вот можно ли "размыть" то, что находится под окном? ;)

19.07.06 17:59
0
Не в сети

BlackTigerAP вопрос уже поднимался в форме

21.07.06 20:02
0
Не в сети

При "обратных" анимациях можно не указывать To (тогда анимация будет от текущего значения к исходному).

08.01.07 18:19
0
Не в сети

И тут спам валит ппц

02.05.11 17:53
0
Для возможности комментировать войдите в 1 клик через

По теме

Акции MSFT
420.55 0.00
Акции торгуются с 17:30 до 00:00 по Москве
Все права принадлежат © ms insider @thevista.ru, 2022
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.072 секунд (Общее время SQL: 0.052 секунд - SQL запросов: 67 - Среднее время SQL: 0.00078 секунд))
Top.Mail.Ru