#020 Применение 3D в WPF — Часть 1

Автор: Topol Воскресенье, Май 6th, 2012 Нет комментариев

Рубрика: Операционные системы

В прошлой статье мы познакомились с основами трехмерной графики в рамках Windows Presentation Foundation . Сегодня мы продолжим знакомство с этой замечательной технологией и научимся расширять возможности наших приложений при помощи 3D.

Создайте новый проект типа «WinFX Windows Application» и задайте ему имя «my3dSample». При выполнении заданий вы можете выбирать проект базирующийся как на Visual Basic, так и на C# в зависимости от ваших предпочтений. По традиции, примеры кода я привожу наVisual Basic  , однако в связи со сложностью данной статьи примеры будут продублированы и на C# .

Данная статья является материалом повышенной сложности. Упражнения подготовлены с расчетом на то, что вы изучали материал предудущих статей.

Выполнение этого задания мы разделим на две части: подготовку базового функционального приложения приложения и расширение возможностей отображения при помощи трехмерной графики. Мы создадим достаточно простое приложение, которое может служить, например, как набор справочных материалов (своеобразная замена «компилированных html-справок» на базе WPF) для некой другой программы. Для того, чтобы вам было проще следовать инструкциям этой статьи, я подготовил схему размещения элементов нашей программы:

Давайте создадим базовую разметку нашего будущего приложения в соответствии с нашей упрощенной схемой. Перейдите в режим редактирования XAML-кода окна Window1 и внесите такой код:

Код:
<Window x:Class=»Window1″
xmlns=»http://schemas.microsoft.com/winfx/2006/xaml/presentation»
xmlns:x=»http://schemas.microsoft.com/winfx/2006/xaml»
Title=»My WPF Help System»
Height=»600″ Width=»800″ MinHeight =»600″ MinWidth =»800″
>

<Grid>
<Grid Background=»Beige»>
<Grid.RowDefinitions >
<RowDefinition Height=»50″ />
<RowDefinition Height=»*» />
<RowDefinition Height=»20″ />

</Grid.RowDefinitions>

<TextBlock  Grid.Row=»0″ Grid.RowSpan=»2″  Margin=»20,5,20,5″
TextAlignment=»left»
Foreground=»Gray»
FontStyle=»Italic» FontSize=»30pt» FontFamily=»Calibri»
FontWeight=»bold»>Справочная система</TextBlock>

<Grid Grid.Row=»1″>
<Rectangle Fill=»white» RadiusX=»14″ RadiusY=»14″ Margin=»10″
Stroke=»sc#1.000000, 0.250141, 0.333404, 0.884413″
StrokeDashArray=»2″/>

<DockPanel DockPanel.LastChildFill=»True»   Margin=»20″>
<Grid  Width=»200px»>
<Rectangle Fill=»Beige» RadiusX=»10″ RadiusY=»10″
Stroke=»sc#1.000000, 0.250141, 0.333404, 0.884413″
StrokeDashArray=»2″ />

<DockPanel Margin=»7″ DockPanel.LastChildFill=»False» >

<TextBlock Margin=»0,0,0,10″   Text=»Статьи:»
Foreground=»Gray» TextAlignment=»center»
FontWeight=»Bold» FontSize=»14pt»
DockPanel.Dock=»top»  />
<StackPanel VerticalAlignment=»Stretch» Margin=»10″>

<RadioButton Content =»Раздел справки 1″
Checked=»sampleSelected»/>
<RadioButton Content =»Раздел справки 2″
Checked=»sampleSelected»/>
<RadioButton Content =»Раздел справки 3″
Checked=»sampleSelected»/>
</StackPanel >
</DockPanel>
</Grid>

<DockPanel Name=»Details»  DockPanel.LastChildFill=»True»>

<Grid >

<Rectangle Fill=»White» RadiusX=»14″ RadiusY=»14″
Margin=»0,0,0,8″ StrokeDashArray=»2″/>
</Grid>

</DockPanel>

</DockPanel>
</Grid>
</Grid>
</Grid>
</Window>

Этот код выглядит несколько запутанным, однако он очень прост — мы использовали многочисленные вложенные контейнеры, чтобы добиться необходимого расположения элементов, и нужного оформления. Мы использовали уже знакомые контейнеры: Grid, StackPanel, DockPanel. Вам не знакомо только одно свойство — DockPanel.LastChildFill — оно указывает, необходимо ли последнему элементу входящему в стостав DockPanel растягиваться, чтобы занять все свободное место или нет. Так же обращаю ваше внимание, что для всех трех элементов типа RadioButton мы задали ссылку на событие Checked как «sampleSelected». Поэтому, чтобы наш проект мог удачно запуститься нам необходимо добавить обработчик этой функции в код программы. Переключитесь в режим редактирования кода VB/C#:

Код VB:

Код:
Private Sub sampleSelected(ByVal sender As Object, _
ByVal args As RoutedEventArgs)

End Sub

B[]Код C#:

Код:
private void sampleSelected(object sender, RoutedEventArgs args)
{

}

Также, если вы используете C#, измените строку XAML-кода x:Class=»Window1″ на x:Class=»my3dSample.Window1″ в описании свойств окна Window1, в противном случае возможна ошибка компиляции, связанная с отсутствием нужного пространства имен.

Давайте запустим проект:

Итак, мы сделали необходимую разметку. Но возможно, вы думаете, что использование RadioButton нецелесообразно и нелогично в рамках нашей задачи. Вы были бы правы, если бы мы программировали на .NET 2.0 однако при помощи WPF мы изменим внешний вид этих элементов так, что они перестанут быть похожими на переключатели и станут… кнопками. Конечно же, мы применим для достижения этой цели стили. Мы уже неоднократно приминяли подобную технологию для создания неординарных контролов. Вы знаете, что стили можно описать в секции Window.Resources, также их можно описать в отдельном файле словаря ресурсов (Resource Dictionary) и подключить к файлу Window1.xml. Сегодня мы воспользуемся еще одним способом размещения ресурсов. Вы наверняка замечали, что в проекте помимо файла Window1.xaml всегда присутствует еще один файл — App.xaml. Перейдите в редактирование XAML-кода этого файла и внесите изменения в секцию Application.Resources:

Код:
<DrawingBrush x:Key=»MyGridBrushResource»
Viewport=»0,0,10,10″
ViewportUnits=»Absolute» TileMode=»Tile»>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush=»White»>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect=»0,0,1,1″ />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Geometry=»M0,0 L1,0 1,0.1, 0,0.1Z»
Brush=»#CCCCFF» />
<GeometryDrawing Geometry=»M0,0 L0,1 0.1,1, 0.1,0Z»
Brush=»#CCCCFF» />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>

<DrawingBrush x:Key=»MyBlueGridBrushResource»
Viewport=»0,0,10,10″
ViewportUnits=»Absolute» TileMode=»Tile»>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush=»#CCCCFF»>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect=»0,0,1,1″ />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Geometry=»M0,0 L1,0 1,0.1, 0,0.1Z»
Brush=»LightGray» />
<GeometryDrawing Geometry=»M0,0 L0,1 0.1,1, 0.1,0Z»
Brush=»LightGray» />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>

<GradientStopCollection x:Key=»MyGlassGradientStopsResource»>
<GradientStop Color=»WhiteSmoke» Offset=»0.2″ />
<GradientStop Color=»Transparent» Offset=»0.4″ />
<GradientStop Color=»WhiteSmoke» Offset=»0.5″ />
<GradientStop Color=»Transparent» Offset=»0.75″ />
<GradientStop Color=»WhiteSmoke» Offset=»0.9″ />
<GradientStop Color=»Transparent» Offset=»1″ />
</GradientStopCollection>

<LinearGradientBrush x:Key=»MyGlassBrushResource»
StartPoint=»0,0″ EndPoint=»1,1″ Opacity=»0.75″
GradientStops=»{StaticResource MyGlassGradientStopsResource}» />

<Style TargetType=»{x:Type TextBlock}»>
<Setter Property=»TextBlock.HorizontalAlignment» Value=»Left» />
<Setter Property=»TextBlock.FontFamily» Value=»Verdana» />
<Setter Property=»TextBlock.TextWrapping» Value=»Wrap» />
<Setter Property=»TextBlock.MaxWidth» Value=»400″ />
</Style>

<Style x:Key=»CodeTextBlockStyle» TargetType=»{x:Type TextBlock}»>
<Setter Property=»HorizontalAlignment» Value=»Left» />
<Setter Property=»FontFamily» Value=»Courier New» />
<Setter Property=»TextWrapping» Value=»Wrap» />
<Setter Property=»MaxWidth» Value=»400″ />
<Setter Property=»Background» Value=»#33CCCCCC» />
<Setter Property=»Padding» Value=»5″ />
</Style>

<Style x:Key=»MyCodeSpanStyle» TargetType=»{x:Type Span}»>
<Setter Property=»FontFamily» Value=»Courier New» />
<Setter Property=»Background» Value=»#33CCCCCC» />
</Style>

<Style x:Key=»MyHeadingSpanStyle» TargetType=»{x:Type Span}»>
<Setter Property=»FontFamily» Value=»Palatino Linotype» />
<Setter Property=»FontWeight» Value=»Bold» />
</Style>

<Style TargetType=»{x:Type RadioButton}»>
<Setter Property=»Background» Value=»White» />
<Setter Property=»Template»>
<Setter.Value>
<ControlTemplate TargetType=»{x:Type RadioButton}»>
<Grid Width=»{TemplateBinding Width}»
Height=»{TemplateBinding Height}» ClipToBounds=»true»>

<Rectangle x:Name=»outerRectangle»
HorizontalAlignment=»Stretch»
VerticalAlignment=»Stretch» Stroke=»{TemplateBinding Background}»
RadiusX=»20″ RadiusY=»20″ StrokeThickness=»5″ Fill=»Transparent» />

<Rectangle x:Name=»innerRectangle»
HorizontalAlignment=»Stretch»
VerticalAlignment=»Stretch» Stroke=»Transparent»
StrokeThickness=»20″
Fill=»{TemplateBinding Background}» RadiusX=»20″ RadiusY=»20″ />

<Rectangle x:Name=»glassCube» HorizontalAlignment=»Stretch»
VerticalAlignment=»Stretch»
StrokeThickness=»2″ RadiusX=»10″ RadiusY=»10″ Opacity=»0″
Fill=»{StaticResource MyGlassBrushResource}»
RenderTransformOrigin=»0.5,0.5″>
<Rectangle.Stroke>
<LinearGradientBrush StartPoint=»0.5,0″ EndPoint=»0.5,1″>
<LinearGradientBrush.GradientStops>
<GradientStop Offset=»0.0″ Color=»LightBlue» />
<GradientStop Offset=»1.0″ Color=»Gray» />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Stroke>

<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform />
<RotateTransform />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<DockPanel>
<ContentPresenter x:Name=»myContentPresenter» Margin=»15″
Content=»{TemplateBinding  Content}»
TextBlock.Foreground=»Black» />
</DockPanel>
</Grid>
<ControlTemplate.Triggers>

<Trigger Property=»IsFocused» Value=»true»>
<Setter Property=»Rectangle.Opacity» Value=»1″
TargetName=»glassCube» />
<Setter Property=»Rectangle.Opacity» Value=»1″
TargetName=»innerRectangle» />
</Trigger>

<EventTrigger RoutedEvent=»Mouse.MouseEnter»>
<EventTrigger.Actions>
<BeginStoryboard Name=»mouseEnterBeginStoryboard»>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName=»glassCube»
Storyboard.TargetProperty=»(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)»
From=»1″ To=»0.9″ Duration=»0:0:0.5″ />
<DoubleAnimation
Storyboard.TargetName=»glassCube»
Storyboard.TargetProperty=»(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)»
From=»1″ To=»0.9″ Duration=»0:0:0.5″ />

<DoubleAnimation
Storyboard.TargetName=»outerRectangle»
Storyboard.TargetProperty=»(Rectangle.RadiusX)»
From=»20″ To=»0″ Duration=»0:0:0.5″ />

<DoubleAnimation
Storyboard.TargetName=»outerRectangle»
Storyboard.TargetProperty=»(Rectangle.RadiusY)»
From=»20″ To=»0″ Duration=»0:0:0.5″ />

<DoubleAnimation
Storyboard.TargetName=»glassCube»
Storyboard.TargetProperty=»(Rectangle.Opacity)»
From=»0″ To=»1″ Duration=»0:0:0.1″ />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent=»Mouse.MouseLeave»>
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName=»outerRectangle»
Storyboard.TargetProperty=»(Rectangle.RadiusX)»
From=»0″ To=»20″ Duration=»0:0:0.5″ />

<DoubleAnimation
Storyboard.TargetName=»outerRectangle»
Storyboard.TargetProperty=»(Rectangle.RadiusY)»
From=»0″ To=»20″ Duration=»0:0:0.5″ />

<DoubleAnimation
Storyboard.TargetName=»glassCube»
Storyboard.TargetProperty=»(Rectangle.Opacity)»
From=»1″ To=»0″ Duration=»0:0:0.1″ />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent=»RadioButton.Checked»>
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName=»glassCube»
Storyboard.TargetProperty=»(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)»
To=»0.1″ Duration=»0:0:0.1″ AutoReverse=»True» />
<DoubleAnimation
Storyboard.TargetName=»glassCube»
Storyboard.TargetProperty=»(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)»
To=»0.1″ Duration=»0:0:0.1″ AutoReverse=»True» />
<DoubleAnimation
Storyboard.TargetName=»innerRectangle»
Storyboard.TargetProperty=»(Rectangle.Opacity)»
To=»0″ Duration=»0:0:0.5″ />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent=»RadioButton.Unchecked»>
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName=»innerRectangle»
Storyboard.TargetProperty=»(Rectangle.Opacity)»
To=»1.0″ Duration=»0:0:0.5″ />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Структура подобного кода уже вам знакома — мы создали несколько кистей и определили новые стили для элементов RadioButton. При помощи несложной анимации мы придали им необычное поведение при наведении мыши. Обратите ваше внимание не то, что при внесении ресурсов в секцию Application.Resources, вам не нужно ничего подключать к файлу основного окна. Все будет работать сразу. Запустите проект:

Посмотрите — внешне от RadioButton не осталось и следа! Мы продолжим выполнение этого задания в статье №021 поэтому сохраните свой проект.

Источник: thevista.ru

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты