윈도우 앱개발을 향하여

블로그 이미지
윈도우 10 스토어에 앱을 개발해 올리는 것을 목표로 하고 있습니다. 비전공자가 독학으로 시도하는 일이어서 얼마나 걸릴지 모르겠지만... 아무튼 목표는 그렇습니다!!
by 코딩하는 경제학도
  • Total hit
  • Today hit
  • Yesterday hit

'XAML Layout in Depth'에 해당되는 글 6건

  1. 2017.12.22
    (XAML Layout in Depth) Advanced Topics
  2. 2017.12.20
    (XAML Layout in Depth) Transformations and Projections
  3. 2017.12.19
    (XAML Layout in Depth) Panels
  4. 2017.12.16
    (XAML Layout in Depth) Layout-properties of Element
  5. 2017.12.15
    (XAML Layout in Depth) Layout Basics 2
  6. 2017.12.13
    (XAML Layout in Depth) Layout Basics 1

Copyright

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 마지막 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents).


Content

1. Layout Basics 1

2. Layout Basics 2

3. Layout properties of Element

4. Panels

5. Transformations and Projections

6. Advanced Topics


Outline

The Grid : Overlay and shared size groups

Layout the content of a Control

Change the Panel of an ItemsControl

ScrollViewer and Viewbox

Animated move of elements in a Panel




The Grid as Overlay-container

If you don't specify RowDefinitions and ColumnDefinirions the Grid is one single cell.

Elements in one cell are drawn over each other in the order that defined in XAML(the last element is on top)

So the Grid is the perfect panel to overlay items.


eg. Loading-overlay

<Grid>

<!-- Content -->

<some panel> ...content... </some panel>


<!-- Loading overlay -->

<Gird                                        //custom control로 만들어 따로 빼두는게 이용에 편리하다.

Background="#AAFFFFFF"        //FFFFFF == white, alpha channel of AA == a bit transparent

d:IsHidden="True"                  //Hidden this element to do not overlay elements on the designer

Visibility="{x:Bind ....IsLoading}" //Data binding 로딩이 끝나면 사라질 수 있도록

>

<ProgressRing .../>

</Grid>

</Gird>



The Grid : Shared Size Groups (WPF only)

Share the same size between different ColumnDefinitions or RowDefinitions, Even across multiple Grid-instances

Set the SharedSizeGroup property on RowDefinitions or ColumnDefinitnons, its of type string(without space, not start with number).

Then Set the attached property Grid.IsSharedSizeScope on a parent to true.


eg. <StackPanel Grid.IsSharedSizeScope="True">

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition SharedSizeGroup="myGroup">

<ColumnDefinition/>

</Grid.ColumnDefinitions>

</Grid>


<Grid>

<Grid.ColumnDefinitions>    //Size of this column is sync with the above column with SharedSizeGroup

<ColumnDefinition SharedSizeGroup="myGroup">

<ColumnDefinition/>

</Grid.ColumnDefinitions>

</Grid>

</Grid>


# Star-sized columns or rows with a SharedSizeGroup are treated as Auto at runtime.



Layout the Content of a Control

Let's assume that the content of a Control is a FrameworkElement which contains Horizontal/VerticalAlignment and Margin

The Control class is a subclass of FrameworkElement and it defines Horizontal/VerticalContentAlignment and Padding to layout its content


When you set Horizontal/VerticalContentAlignment property, the Control internally sets the Horizontal/VerticalAlignment on its Content, and there is a Padding property that sets the Margin property on the Content. All those properties are wired together in the Control template of a Control.


eg.  //To Strecth Contents of ListView

<ListView HorizontalAlignment="Stretch"

HorizontalContentAlignment="Stretch"    //Have effect in WPF

Background="YellowGreen" ItemsSource="{x:Bind peaple}">

        <ListView.ItemContainerStyle>

            <Style TargetType="ListViewItem">

                <Setter Property="HorizontalContentAlignment"  Value="Stretch" />   //Have effect in UWP

            </Style>

        </ListView.ItemContainerStyle>

        <ListView.ItemTemplate>

            <DataTemplate x:DataType="model:Person">

                <Border HorizontalAlignment="Stretch" Background="Orange" CornerRadius="5" Margin="1"> //No effect

                    <StackPanel Margin="5">

                        <TextBlock Text="{x:Bind Name}"/>

                        <TextBlock Text="{x:Bind Age}"/>

                    </StackPanel>

                </Border>

            </DataTemplate>

        </ListView.ItemTemplate>

    </ListView>



Change the Panel of an ItemsControl

An ItemsControl can contain many objects. Typical ItemsControls are the ListView and ComboBox


To change the panel there is two options

1. Set the ItemsPanel property of ItemsControl

Assign an ItemsPanelTemplate to this property and specify the panel in the ItemsPanelTemplate


2. Assign a new ControlTemplate to the Template property of ItemsControl

Inside of that Template, create a Panel and Set the IsItemsHost property(defined in the Panel class) to true

(This property is readonly in WinRT)


Normally change the Panel of an ItemsControl, choose option 1.

When you are defining the new ControlTemplate to create a new look for your ItemsControl, choose option 2



When There's Not Enough Space

When there is not enough space for panel, panels are just clipping their elements.

1. Put your panel into a ScrollViewer, it supports Horizontal/Vertical scroll bars

2. Or put your panel into a Viewbox, it will just shrink or scale your panel



The ScrollViewer

To display a vertical and horizontal scrollbar

ScrollViewer class inherits from ContentControl, so it has a Content property of type Object (like button)

Control the scrollbar visibility with the properties VerticalScrollBarVisibiity(default Visible) and HorizontalScrollBarVisibility(default Disabled), both properties take a value of the ScrollBarVisibility enumeration(Disabled, Auto, Hidden, Visible)


# Some ItemControls, like the ListView, have an internal ScrollViewer, it is defined in the ControlTemplate of the ListView

Use attached properties to modify the internal ScrollViewer


eg. <ListView ScrollViewer.VerticalScrollBarVisibility="Auto" />



The Viewbox

To stretch an element to the available space

The Viewbox class inherits via Decorator from FrameworkElement in WPF. In WinRT, Viewbox inherits FrameworkElement directly


The Decorator class defines a child property that takes a single UIElement. In the WinRT, the child property is directly defined on the Viewbox itself. ViewBox has a child property anyway, so in XAML you can just place any UIElement inside of Viewbox. Then the Viewbox will automatically stretch the element based on the available space.


To control the stretching, the Viewbox has a Stretch property that takes a value of the Stretch enumeration

None : no stretching (DesiredSize)

Fill : aspect ratio changes to fill the available space

Uniform(default) : aspect ratio never changed, there is leftover space

UniformToFill : aspect ratio never changed, and fill the leftover space 


and StretchDirection property of type enum StretchDirection

UpOnly : only grow (DesiredSize가 최소크기이고 그 이하로 공간이 부족해지면 clip된다)

DownOnly : only shrink (DesiredSize가 최대크기)

Both(default) : can be shrink and grow



Animated Move of Elements in a Panel

In some scenarios an animated move makes the user experience much better

Instead of using a TranslateTransform, you can also use the FluidMoveBehavior that animates a change in the position of an element (high-level class), it's like an animated TranslateTransform, but it's much simpler to use


To use it open up Blend and attach the FluidMoveBehavior to a Panel (asset -> behavior -> drap&drop -> property setting)

In Blend, There's also a FluidMoveSetTagBehavior that allows you to define a starting point for the move


그러나 FluidMoveBehavior가 UWP project에 기본적으로 들어있지는 않았다, Nuget을 통해 받아 사용하는 듯 하나, 아직 Behavior와 관련한 내용을 모르겠다. Pluralsight에서 관련 강의를 찾았다(link).




Summary (생략)


출처

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 마지막 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.

AND

Copyright

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 네번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents).


Content

1. Layout Basics 1

2. Layout Basics 2

3. Layout properties of Element

4. Panels

5. Transformations and Projections

6. Advanced Topics


Outline

Transformations

Get the position of an element

Projections



Transformations

Defines how to map points from one coordinate space into another one

A transformation can be used on an element to - rotate it, scale it,  skew it, translate it(move it)


Transformation Classes

RotateTransform class

ScaleTransform class

SkewTransform class

TranslateTransform class

MatrixTransform class

All transformations in the two-dimensional space can be described by a 3x3 matrix

While the Rotate/Scale/Skew/TranslateTransform class is high-level classes, the MatrixTransform class is low-level. It allows you to change the 3x3 matrix directly to rotate, scale, skew, translate an element.

TransformGroup class (to combine transformations)

CompositeTransform class (not in WPF)

Single transform class that can rotate, scale, skew, and translate an element


These all Transform classes inherit from the Transform class. The Transform class is the base class for two-dimensional transformations.

Also Transform class inherits from GeneralTransform. The GeneralTransform contains the base logic for transformations between points and rectangles.


All the Transform classes are DependencyObjects and their properties have been implemented as Dependency properties. That means you can use the properties in a style, you can use them as a target for a data binding, or you can event animate them.



LayoutTransform vs RenderTransform

On a FrameworkElement, there are LayoutTransform and RenderTransform properties. Both are of type Transform.


A Transform can be assigned to an element's...

1. LayoutTransform property (WPF only)

The Transform that assigned to the LayoutTransform property is applied before the layout process. 따라서 layout에 영향을 미치므로, 예를들어 StackPanel의 child중 하나를 rotate시켰다면 그 child는 더 많은 Heigth/Width를 차지한 채 layout에 표시된다DesiredSize is bigger). So the layout process runs whenever you change the transform.


2. RenderTransform property (all XAML-based frameworks)

The Transform that assigned to the RenderTransform property is applied after the layout process. 따라서 layout에 영향을 미치지 않으므로, 에를들어 StackPanel의 child중 하나를 rotate시켰다면 그 child만 회전하고 나머지 child의 위치에 영향을 주지 않는다. Whenever you change the transformation that has been assigned to the RenderTransform property, only a new rendering will occur, but no layout process will be executed. So when you plan to change the Transform object at runtime, you should assign it to the RenderTransform property.


The Origin of a RenderTransform

Layout process가 RenderTransform과 무관하기 떄문에 Origin을 필요로 한다.

Origin is defined in the RenderTransformOrigin property(Type Point) that is defined in the UIElement class.

Default value is 0, 0. Specified origin is relative to the size of an element (center of element 0.5, 0.5, bottom right corner 1, 1)



Rotate, Scale and Skew

RotateTransform : Angle property to define clockwise rotation (default 0)

ScaleTransform : Properties ScaleX/ScaleY to define scale (both default value 1 == scale is by default 100%)

SkewTransform : Properties AngleX/AngleY to define skew angle (defualt 0)


All three Transforms have the Properties CenterX and CenterY (default 0) : Use them to define an absolute (pixel-based) origin

Element에 RenderTransformOrigin property를 지정하는 대신에, you could also define the origin by setting the properties CenterX and CenterY on your Transform object. When you group multiple transforms with the TransformGroup, the properties CenterX and CenterY allow you to define a different origin for each transform in that TransformGroup.



Get the Position of an Element


WinRT eg. 

//Call TransformToVisual method on green element and pass orange element as parameter, then returns GeneralTransform object

//GeneralTransform contains base logic for transformations between points and rectangles.

GeneralTransform generalTransform = green.TransformToVisual(orange);


//Call TransformPoint method on the GeneralTransform object with a new Point that contains default 0 for X and Y

//then it returns a point that contains Horizontal/Vertical distance between default value and generalTransform 

Point point = generalTransform.TransformPoint(new Point());

//In WPF Transform method instead of TransformPoint method


WPF (alternative)

Point pint = green.TranslatePoint(new Point(), orange);



Translate an Element

TranslateTransform class has the properties X and Y to define the translation(move)

The TranslateTransform has no effect when it is assigned to the LayoutTransform property of an element, because the transformation occurs before the layout process and the layout process arranges element and gives it a final position. So Assign it to the RenderTransform property


eg.    private void Rectangle_Tapped(object sender, TappedRoutedEventArgs e)

        {

            var element = e.OriginalSource as FrameworkElement;

            if (element != null)

            {

//Get the position of target (where the rectangle will positioned)

                var generalTransform = target.TransformToVisual(element);

                var point = generalTransform.TransformPoint(new Point());


//Set TranslateTransform to element's RenderTransform

                var translateTransform = element.RenderTransform as TranslateTransform;

                if (translateTransform == null)

                {

                    translateTransform = new TranslateTransform();

                    element.RenderTransform = translateTransform;

                }


//Translate(move) the element to the position of the target

//Here can be replaced to an animation

                translateTransform.X = point.X;

                translateTransform.Y = point.Y;

            }

        }



MatrixTransform

Low-level class to create custom 2D-transformations

Matrix-Property contains the 3x3 affine transformation matrix

The Matrix can be modifed to rotate scale, skew and translate an element (need linear algebra)



Combine Transformations

Instead of a MatrixTransform, you can also use the TransformGroup to combine transformations(much simpler).

TransformGroup has a Children property of type TransformCollection and inherits from Transform, can be assign it either to the RenderTransform or to the LayoutTransform property of an element.


eg. <Rectangle.RenderTransform>

           <TransformGroup>

               <RotateTransform Angle="45" />

               <ScaleTransform ScaleX="2" ScaleY="2"/>

           </TransformGroup>

     </Rectangle.RenderTransform>



There is another class to combine multiple transformations (not available in WPF) : CompositeTransform

CompositeTransform contains Rotation, ScaleX/ScaleY, SkewX/SkewY, TranslateX/TranslateY properties



Projections (Not available in WPF)

A projection is a perspective transformation of an element

The perspective transformation is a 3D-like effect that you can apply to your element.


In Silverlight, this Projection class is abstract.

In the WinRT, the constructor is protected.


you can assign PlanProjection or Matrix3DProjection to the Projection property of any UIElement.





PlaneProjection

To rotate an element around the axis X, Y and Z

It contains the properties RotationX, RotationY, and RotationZ (angle in degrees, default 0) and CenterOfRotationX, CenterOfRotationY, CenterOfRoationZ properties define the center of rotation.


CenterOfRotationX/Y contain a relative value (default 0.5)

CenterOfRoataionZ contain a absolute value in pixels (default 0, <0 means center of rotation is behind the element, >0 front of it)


Translate your element with offsets

LocalOffsetX/Y/Z : Translation before rotation

GrobalOffsetX/Y/Z : Translation after rotation (just move the center of rotation)



Matrix3DProjection

Low-level class to create custom 3D-transformations

ProjectionMatrix property contains the 4x4 transform matrix (Matrix3D) used for the projection



Summary (생략)


출처

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 네번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.

AND

Copyright

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 세챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents).


Content

1. Layout Basics 1

2. Layout Basics 2

3. Layout properties of Element

4. Panels

5. Transformations and Projections

6. Advanced Topics


Outline

Elements with children

Panel classes (Grid, StackPanel, Canvas, WrapPanel, DockPanel, VariableSizeWrapGrid)

Build application layouts



Elements with children

In XAML-based applications, there are four main categories of elements that can have children.


1. Single UIElement

Child Property of type UIElement.

(In the WPF, Decorator class is a base class for those elements. Decorator class가 child 속성을 정의한다. Well known subclasses of Decorator are Border and Viewbox. WinRT에는 Decorator class는 없지만 Border, Viewbox class는 여전히 존재하며 UIElement타입의 child property를 가지고 있다.)


2. Many UIElements (of type Panel, 이 글의 주된 타겟)

Children property of type UIElementCollection


3. Single object

Content property of type Object

Those elements inherit from the ContentControl class, which defines that Content property. ContentControl은 예를 들어 Button class, ScrollViewer class, Window class(WPF) 등이다.


4. Many Objects

Items property of type ItemsCollection and in addition, an ItemsSource property of type IEnumerable.

Those two properties are implemented in the ItemsControl class이며 ComboBox, ListView가 유명한 subclass이다.


ContentControl이나 ItemsControl에는 한가지 규칙이 있다. 만약 object가 UIElement라면, it is rendered in its normal way. object가 UIElement가 아니라면, the result of the ToString method is displayed in a text block. 이것을 피하기 위해 you can create a user interface for your object. You do this by specifying a data template. ContentControl class는 Content property와 함께 ContentTemplate property를 가지며, ContentTemplate property는 user interface(for the object that is stored in the Content property)를 지정할 data template를 받는다. 마찬가지로 ItemsControl class도 ItemTemplate property를 가진다. ItemsTemplate property is also of type DataTemplate unless you specify the user interface for a single object in that ItemsControl(For more about data template, see link). Internally an ItemsControl is using a panel to layout its children.



The Base Class : Panel

The Base class for all the Panels in the XAML-based frameworks is the class Panel. It directly inherits from FrameworkElement.


- Children property (of type UIElementCollection)


- Background property

Default is null, 만약 panel에 input event handler를 만들었을 때 Background가 null이면 event가 실행되지 못한다. 색상을 원하지 않는 경우라면 Transparent를 두면 된다.


- Attached property ZIndex(WPF의 Panel class만 contains the Zindex property, 다른 경우 ZIndex는 Canvas class에 정의되어 있다)



Panel-subclasses in WPF and WinRT


WPF & WinRT

Grid, Canvas, StackPanel

VirtualizingStackPanel : used inside of an ItemsControl. It does a UI virtualization for the items in that ItemsControl.

That means that the UI for items that are by far out of the view is not created by default.

The UI for those items is only created when you scroll to them. So such a VirtualizingStackPanel will gain performance when you have a lot of items in your ItemsControl. 


WPF specific panel 

DockPanel : allows to dock elements at the Left, Top, Right, Bottom

WrapPanel : stacks elements per default in a horizontal way, and it automatically inserts a line break if there is not enough space.

UniformGrid : simple Grid where all cells have the same size

etc....


WinRT specific panel

VariableSizedWrapGrid : create a kind of Grid layout and each cell can have a variable size

SwapChain : it is used as a hosting suffice to render direct X content in your XAML application

Many of the other panels available in the WinRT can only be used as a panel in an ItemsControl(따라서 WinRT로 layout을 만들때는 Grid, StackPanel, VariableSizedWrapGrid 등 뿐이다.)



The Grid

Arranges children in rows and columns

To define rows and columns, use the properties RowDefinitions and ColumnDefinitions.


To arrange your children, use the attached properties Grid.Row, Grid.Column, Grid.RowSpan, Grid.ColumnSpan.

(Grid.Row과 Grid.Column의 디폴트 값은 0이고, Grid.RowSpan과 Grid.ColumnSpan의 디폴트 값은 1이다.)


RowDefinition class와 ColumnDefinition class는 세개의 중요한 속성을 가진다.

- Height(of type GridLength), MinHeight(of type double), MaxHeight(of type double)

- Width(of type GridLength), 위와 동일


The GridLenght struct supports 3 different units (GridUnitType) that you can use to set the Height or Width.

Those three units are defined in the GridUnitType enumeration : Auto, Pixel, Star(default)

For XAML, a TypeConverter exists that allows you a very simple usage of those three different units.


The GridSplitter (WPF, Silverlight only, for UWP see this link)

The GridSplitter is a control that allows the user to resize the rows and columns in a Grid.

By default, the GridSplitter resizes rows or columns based on its alignment.



The Canvas

Position children explicitly with coordinates

use the attached properties (Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom)

For overlapping elements, either use Canvas.ZIndex (in WPF Panel.ZIndex) or change the order of the children


Canvas is not for layout, use the Canvas for graphical stuff.



The StackPanel

Stacks elements in one line

The Orientation property can be set to Vertical(default) or Horizontal



The WrapPanel (WPF only)

Stacks elements in one line and adds a linebreak when there's not enough space left

The Orientation property can be set to Vertical or Horizontal(default)

WrapPanel은 DesiredSize Width로 element를 dispaly하고, 모든 elements in a row는 가장 큰 element Height에 맞춰 stretch된다.

모두 동일한 크기를 가지게 하려면 WrapPanel의 ItemWidth, ItemHeight를 설정해주면 된다.


(WrapPanel in UWP, see link)



The DockPanel (WPF only)

Docks elements at the left, top, right, and bottom

Set the attached property DockPanel.Dock on the children (Dock-enum Left(default), Top, Rigth, Bottom)

By default the LastChildFill property is true, so the last child fills the leftover space.

DockPanel can be used as a RootPanel for the layout of application, but there is no Splitter control


다른 XAML-base application과의 연동을 고려한다면 Grid를 사용하는 편이 낫다.



The VariableSizedWrapGrid (WinRT only)

Arranges children in rows and columns

Orientation property, Vertical(default, stacks children in columns) and Horizontal(stacks children in rows)

Define equal size for all children with ItemWidth and ItemHeight


MaximumRowsOrColumns property to define when break occurs(default -1)

창의 크기가 줄어들면 그에 맞추어 element가 재배열되지만 공간이 남더라도 아래의 사진처럼 아래로 2칸까지만 내려가고 오른쪽으로 배열되도록 설정할 수 있다(MaximumRowOrColumns = 2, Orientation = Vertical)


Attached Properties for children

VariableSizedWrapGrid.RowSpan

VariableSizedWrapGrid.ColumnSpan




Summary (생략)


출처

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 세번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.

AND

Copyright

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 두번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents).


Content

1. Layout Basics 1

2. Layout Basics 2

3. Layout properties of Element

4. Panels

5. Transformations and Projections

6. Advanced Topics


Outline

Alignments, Width Height, Margin

The Visibility

Using the Designer



Alignments

To align your element in its parent container, the FrameworkElement class has two properties.


HorizontalAlignment (Left, Right, Center, Stretch)

VerticalAlignment (Top, Bottom, Center, Stretch)


They only have an effect when the FinalSize is greater than the DesiredSize. (FinalSize > DesiredSize)

Left Right, Center, Top, Bottom, Center 를 하더라도 element는 DesiredSize Width/Height를 가지고, Stretch하면 element가 DesiredSize의 WIdth/Height 보다 커진다.



eg. //DiagonalPanel을 수정해 VerticalStackPanel을 만들었다. Width와 관련된 내용만 수정됨

public class VerticalStackPanel : Windows.UI.Xaml.Controls.Panel

     {

        protected override Size MeasureOverride(Size availableSize)

        {

            var mySize = new Size();


            foreach(UIElement child in this.Children)

            {

                child.Measure(availableSize);


                //가장 큰 너비를 가진 child의 너비를 mySize.Width로 넣어준다.

                mySize.Width = Math.Max(mySize.Width, child.DesiredSize.Width);

                mySize.Height += child.DesiredSize.Height;

            }


            return mySize;

        }


        protected override Size ArrangeOverride(Size finalSize)

        {

            var location = new Point();


            foreach(UIElement child in this.Children)

            {

                //child의 너비에 VerticalStackPanel의 너비를 넘겨준다.

                child.Arrange(new Rect(location, new Size(finalSize.Width, child.DesiredSize.Height)));

                location.Y += child.DesiredSize.Height;

            }


            return finalSize;

        }

    }


//Child element의 DesiredSize.Width보다 fianlSize.Width가 더 크므로, HorizontalAlignment의 효과를 볼 수 있다.

//VerticalAlignment의 경우는 child.DesiredSize.Height가 finalSize가 되었으므로 그 효과를 볼 수 없다.



Width and Height

With the properties Width and Height you give your element an explicit size, and Default-Value is Double.NaN


To access the final size (the size that is calculated during the layout process) use ActualWidth/ActualHeight (readonly)

ActualWidth/ActualHeight는 Arrange()가 호출될때 값이 채워지고, they contain the FinalSize(FinalSize is used in the render step).

ActualWidth/ActualHeight의 값이 변하면 LayoutUpdated-event가 발생한다. This event is fired whenever a layout process has occurred(and that means the ActualWidth/ActualHeight properties of your element have changed). 따라서 LayoutUpdated-event내에서 ActualWidth/ActualHeight에 접근하는 것은 좋은 방법이다.


Explicit하게 Width/Height에 값을 넣으면 element의 final size will be based on those values(DesiredSize에 들어간다).

- Element does not resize anymore (fixed element)


Size-range : Use the properties MinWidth/MaxWidth, MinHeight/MaxHeight

They allow you to specify Arrange and your element will still resize inside of that range.



The Margin

of type Thickness, For XAML a three TypeConverter exist(값 한개, 두개, 네개를 XAML에서 Margin값으로 설정할 수 있게 한다.)


The Visibility

Takes a value of the Visibility-enum : Visible, Hidden(WPF only), Collapsed


Hidden의 경우 시야에서 사라지지만 여전히 공간을 차지한다, 즉 DesiredSize는 그대로이다.

다른 XAML-based framework들에서는 Opacity = 0, IsHitTestVisible = False 로 하는 방법을 사용할 수 있다.

Collapsed의 경우는 DesiredSize의 Width, Height값이 0이 된다.




Using the Designer (생략)


Summary (생략)


출처

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 두번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.

AND

Copyright

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 첫번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents).


Content

1. Layout Basics 1

2. Layout Basics 2

3. Layout properties of Element

4. Panels

5. Transformations and Projections

6. Advanced Topics



Dependency Property

In XAML-based applications, there are multiple sources for a property. 예를 들어 Style을 통해 Button의 Width를 설정하고, Style안의 Style Trigger로 마우스가 올라갔을때의 Width를 설정할 수 있다. 이것만으로도 이미 two sources for that property를 가진 것이고, 더 많아질 수 있다(Template Trigger, Local Value(버튼에 직접 설정하는 것). Animation etc). For example, each Dependency property has also a default value. So a Dependency Property has different sources, but it can only have one current value. And this current value is dependent of the different sources. That's why the properties are called Dependency Properties.


DependencyObject

이렇게 다양한 source들을 통해 값이 지정될 수 있으므로 어떤 값을 선택할 것인지에 대한 logic이 DependencyObject class에 implement되어 있다(DependencyObject class는 UIElement의 base class이다). DependencyObject에는 SetValueGetValue라는 메소드가 있다. link


eg.  var btn = new Button();

btn.SetValue(Button.WidthProperty, 25.0);


//Button.WidthProperty는 DependencyProperty-Instance로써 it's of type DependencyProperty이다.

//이 DependencyProperty는 static field에 Property라는 suffix를 달고 저장되어있다.


Now behind the scenes, the SetValue call stores a Local Value for the Width property

그러나 GetValue를 호출하면 DependencyObject는 다양한 sources들을 뒤져서 적합한 값을 되돌려준다.



Attached Property

The special kind of a Dependency Property called Attached property is used extensively in layout.

An Attached Property is a property that you attach to any DependencyObject.


There are two kinds of Dependency properties

1. There are those Dependency properties that wrap SetValue and GetValue with a CLR-Property

var btn = new Button();

btn.SetValue(Button.WidthProperty, 25.0);


btn.Width = 25;   //calling SetValue method with Button.WidthProperty and value(25)


Those Dependency properties that use a CLR-Property as a wrapper we normally just call DependencyProperty.


2. The second kind of a Dependency property is wrapping the SetValue and GetValue method with static Set and Get methods

var btn = new Button();

btn.SetValue(Grid.RowProperty, 1); //pass in a Dependency property that is defined in another class(Grid.RowProperty)


Grid.SetRow(btn, 1);


Grid.RowProperty는 Grid class에 정의되있지만 can set a value for this property on a Button object(attach a value for this property to the Button object). For those properties, there exists static methods, in this case, the SetRow method defined in the Grid class. where you pass in your DependencyObject and the value. As with the CLR-Property, this static method just calls SetValue behind the scenes. So in this case, we call SetValue on the Button instance that is passed as a first parameter to the SetRow method.


Those properties that are attached to specific objects are called AttachedProperty.

For Attached properties, Attached-Property-Syntax for XAML exist


eg.  <Button Grid.Row="1"  .../>

Behind the scenes, the framework is calling the SetValue method on the Button object and passing in as a first parameter Grid.RowProperty and as a second parameter, the value 1.



#Two snippets for Dependency properties

propdp : for normal Dependency Property wrapping the SetValue, GetValue method with CLR-Property

propa : for Attached Property wrapping SetValue, GetValue with two static methods



eg.  public static double GetTop(DependencyObject obj)

{

          return (double)obj.GetValue(TopProperty);

}


public static void SetTop(DependencyObject obj, double value)

{

          obj.SetValue(TopProperty, value);

}


      //To create DependencyProperty, static RegisterAttached method is called

      public static readonly DependencyProperty TopProperty =

          DependencyProperty.RegisterAttached("Top", typeof(double), typeof(SimpleCanvas), new PropertyMetadata(0.0));

//(Name of the property, Type, the ownerclass of the DependencyProperty, Metadata(defines the default value for the Dependency Property)


protected override Size MeasureOverride(Size availableSize)

{

foreach (UIElement child in this.Children)

{

//이 샘플에선 SimpleCanvas의 크기계산엔 관심이 없으나

//child들이 Arrange되기 위해선 Measure를 호출해줄 필요가 있다.

child.Measure(availableSize);

}


return base.MeasureOverride(availableSize);

}


protected override Size ArrangeOverride(Size finalSize)

{

var location = new Point();

foreach (UIElement child in this.Children)

{

//var top = (double)child.GetValue(TopProperty);

//Child로부터 위와 같이 GetValue를 호출해 TopProperty 값을 얻어낼 수도 있지만

//이와 동일한 과정이 GetTop static method에 구현되있다. 따라서 GetTop method를 사용한다.

location.Y = GetTop(child);

child.Arrange(new Rect(location, child.DesiredSize));

}


return base.ArrangeOverride(finalSize);

}



<panel:SimpleCanvas>

    <Button Content="Hello" />

    <Button panel:SimpleCanvas.Top="10" Content="world!" />  //Button의 위치가 위에서 10만큼 아래로 조정된다.

</panel:SimpleCanvas>


//그러나 아직 AttachedProperty 값이 변경되었을 때 Control의 위치가 runtime에 즉시 욺겨지지는 않는다.



Layout Process Execution

The layout process is executed...

1. when an element is rendered its first time

2. when a child element was added or removed from the visual tree

3. when a specific dependency property has changed

4. when InvalidateMeasureInvalidateArrange methods is called on a UIElement

These methods will set the UIElement into an invalidate state and the framework will do a deferred layout process execution. (If you don't want that deferred execution, you can call the UpdateLayout method on your UIElement after you have called InvalidateMeasure or InvalidateArrange. The UpdateLayout method will force a layout process execution.)



Trigger the Layout Process from code

1. Using dependency property metadata (WPF only)

2. Using InvalidateArrage from PropertyChangedCallback (WPF, WinRT, Silverlight, Windows Phone... all XAML-based frameworks)



e.g. 1번의 경우는 DependencyProperty TomProperty = DependencyProperty.RegisterAttached의 4번째 parameter인 PropertyMetadata를 FrameworkPropertyMetadata로 바꾸고 FrameworkPropertyMetadataOption(위 경우엔 AffectParrentArrange)을 선택해 넘겨주면 된다.

(c.f. FrameworkPropertyMetadata는 OnPropertyChanged뿐 아니라 OnPropertyValueChanged 콜백함수도 추가할 수 있다.)


e.g.    //GetTop과 SetTop은 생략

  public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached("Top", typeof(double),                                                          typeof(SimpleCanvas), new PropertyMetadata(0.0, OnTopPropertyChanged));


        private static void OnTopPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

  //First parameter is not SimpleCanvas, its child of SimpleCanvas. (Setting of TopProperty on children)

  //From second parameter, we can access to new and old value and the DependencyProperty itself

        {

            if (d is FrameworkElement child)  //Get child from d as FrameworkElement

            {

                if (child.Parent is SimpleCanvas simpleCanvas)  //Get parent from child = SimpleCanvas

                {

   //We don't need to InvalidateMeasure in this case, we just want to arrange it again.

                    simpleCanvas.InvalidateArrange();


   //Make layout Update right away

                    simpleCanvas.UpdateLayout();

                }

            }

        }



Summary (생략)


출처

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 첫번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.

AND

Copyright

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 첫번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents).


Content

1. Layout Basics 1

2. Layout Basics 2

3. Layout properties of Element

4. Panels

5. Transformations and Projections

6. Advanced Topics


Outline

Layout Base Classes

Layout Process

Dependency and Attached Propertiees



Layout Base Classes

Class hierarchy in XAML


See Basic Element article

http://empisterian.tistory.com/9?category=980707

and Panels and Layout System article

http://empisterian.tistory.com/11?category=980707


UIElement has Measure and Arrage method which are used in the layout process. In addition, the UIElement class has the render transform property that is used to do transformations.


FrameworkElement과 Panel의 내용은 위 두 article에 수록됨




The Layout Process

The Layout Process is executed when an element is rendered its very first time and can be executed again during runtime


The Layout Process is a two step process

1. Measure - Elements calculate their desired size (each element calculates how big it wants to be)

- Calling Measure method on each direct child (after this Measure call, the DesiredSize property of the child is set)

- Access each child's DesiredSize (The parent element can access this DesiredSize and calculate its own desired size)


이 모든 과정은 element tree를 따라 내려간다, 즉 parent element가 자신의 각 direct child들에게 Measure method를 호출하고, 각각의 child들도 자신의 direct child들에게 Measure method를 호출한다. 이 과정이 모두 끝나면 각자 원하는 크기가 DesiredSize property에 저장된 상태가 된다.


2. Arrange - Elements arrange their children

- Calling Arrange on each direct child

(The Arrange method takes a position and a final size, that means the child knows the position where it has to render itself and it also knows the size in which it has to render. So all the information is now clear for the rendering)


3. Rendering - element are rendered on the screen.



Layout Process Participation

Override two methods in a FrameworkElement-subclass


1. MeasureOverride method : Participate in the first step of the layout process, the Measure step.

- Inside of the MeasureOverride method, Call Measure method on each direct child

The MeasureOverride method taskes an availableSize as a parameter which is passed in from the parent in the layout process

- Access each child's DesiredSize

- Return your own desired size


2. ArrangeOverride method : Participate in the second step of the layout process, the Arrange step.

- Inside of the ArrangeOverride method, Call Arrange method on each direct child (pass a location and a final size)

- Return your final size for your element



eg  //Create new Class to make custom Panel

public class DiagonalPanel : Windows.UI.Xaml.Controls.Panel

      {

   //Layout Process의 첫 단계인 Measure단계에 관여하기 위해 MeasureOverride를 정의한다.

   //availableSize is passed in from the parent in the layout process. 이경우엔 DiagonalPanel의 부모로부터 받는다.

        protected override Size MeasureOverride(Size availableSize)

        {

            var mySize = new Size();


//DiagonalPanel의 DesiredSize를 반환하기 위해 element들을 돌면서 계산.

//InternalChildren property in WPF, Children property in UWP from Panel, It contains UIElementCollection

            foreach(UIElement child in this.Children)    

            {

//Call Measure method on each child

                 //여기선 child가 DiagonalPanel보다 작을것이라 기대하며 availableSize를 그대로 넘겼다.

child.Measure(availableSize);


//Measure를 호출하면 child의 DesiredSize property가 채워지고 이걸로 DiagonalPanel의 크기를 계산한다.

                mySize.Width += child.DesiredSize.Width;

                mySize.Height += child.DesiredSize.Height;

            }


            return mySize;

        }

   

  //Layout Process의 두번째 단계인 Arrange단계에 관여하기 위해 ArrangeOverride를 정의한다.

  //부모로부터 finalSize를 통보받고 그 안에서 arrange itself 해야한다. 그리고 layout에 arrange하고 난 실제 크기를 반환.

        protected override Size ArrangeOverride(Size finalSize)

        {

            var location = new Point();


//Children들을 Arrange시킨다.

            foreach(UIElement child in this.Children)

            {

//각 child에게 Arrange method를 호출시켜 Arrange될 장소와 크기를 지정해준다.

//이 경우 대각선으로 child들이 연결되게 장소를 지정하고, 크기는 child의 DesiredSize를 그대로 받아주었다.

                child.Arrange(new Rect(location, child.DesiredSize));


//여기선 다음 child가 지정될 위치를 현재 child의 오른쪽 하단 포인트로 잡아주었다.

                location.X += child.DesiredSize.Width;

                location.Y += child.DesiredSize.Height;

            }


            return finalSize;

        }



//이것으로 child들을 대각선으로 배치하는 새로운 custom panel이 만들어졌고, .xaml에서 컨트롤들을 배치하며 사용가능하다.




Layout Process Internal

WPF                                                                                         WinRT


위에서 우리가 사용한 Measure/Arrange method와 MeasureOverride/ArrangeOverride method 사이에는 Internal logic이 있으며 그것이 몇가지 property들을 관리한다. UIElement의 경우에는 ClipVisibility property가 그렇고, FrameworkElement의 경우에는 Width, Height, Margin property가 그러하다. 

eg. Visibility property를 Collapsed 로 설정하면, 해당 UIElement에서 Measure를 호출한 뒤의 시점에서 DesiredSize property의 Width, Height가 0으로 설정된다. 이렇게 Framework가 몇가지 속성을 관리하므로 개발자가 직접 Layout Process에 관여할 때에도 Child element의 Visibility property를 신경쓸 필요가 없다. Width, Height, Margin의 경우도 그렇다. Width를 설정한 경우, that element will have that DesiredSize Width after a Measure call. So in your layout process participation, you never have to care about if the Width or Height on an element is set. 마찬가지로 Margin의 경우도, Measure method가 호출된 뒤 얻어지는 DesiredSize property는 이미 그 Margin을 포함하고 있는 상태이다. 또한 Panel에 Margin을 설정하는 경우에도, MeasureOverride method의 반환값인 Size(Panel의 DesiredSize)에도 Framework가 개입해 Margin을 자동으로 포함시켜준다.




출처

이 모든 내용은 Pluralsight에 Thomas Claudius Huber가 올린 'XAML Layout in Depth'라는 강의의 첫번째 챕터를 듣고 정리한 것입니다(https://app.pluralsight.com/library/courses/xaml-layout-in-depth/table-of-contents). 제가 정리한 것보다 더 많은 내용과 Demo를 포함하고 있으며 최종 Summary는 생략하겠습니다. Microsoft 지원을 통해 한달간 무료로 Pluralsight의 강의를 들으실 수도 있습니다.

AND

ARTICLE CATEGORY

분류 전체보기 (56)
Programming (45)
MSDN (4)
개발노트 (2)
reference (5)

RECENT ARTICLE

RECENT COMMENT

CALENDAR

«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

ARCHIVE