3.2 Custom Layout rules
The previous section describes the Windows Phone System layout Panel and layout system related principles, then the system layout Panel does not necessarily meet all the layout rules you want to implement, if there are some special layout rules, the System layout panel is not supported, this time need to customize the implementation of a layout panel, Encapsulates the logic of layout rules in a custom layout panel. Then our section starts with a practical need to implement a custom-defined layout panel. The layout law we want to implement in this section is to arrange the sub-elements in the layout panel according to the arrangement rules of the circle, let's take a look at the detailed implementation of this example.
3.2.1 Creating a Layout class
The first thing to do in a Windows Phone panel that implements a custom layout rule like grid and StackPanel is to create a custom layout class. All layout panels need to derive from the Panel class and customize the process of implementing their measurements and permutations. The Children property in the Panel class represents a sub-object within the layout panel, which requires that all sub-objects in the panel be obtained according to the Children property, and then measured and arranged according to the relevant rules.
If our layout class needs to pass in some special parameters outside, then we need to implement the related properties in the Layout class. Of course, like heigh, width and so on these panel class originally supported properties we need not to define, as we in this example to achieve the circular layout, this time is required a circular radius size, the size of this radius can be used as a property to let the value of the outside to pass in, The layout class then handles the measurement and arrangement of the child objects based on the size of the radius. It is important to note that when the custom RADIUS attribute changes, the Invalidatearrange method needs to be called to re-trigger the layout of the arrangement, otherwise the radius will not play any role.
Code Listing 3-2 : Custom layout Rules (source code: Chapter 3rd \examples_3_2)
Let's take a look at the custom Circlepanel class:
Public classCirclepanel:panel {//Custom RADIUS Variables Private Double_radius =0; PublicCirclepanel () {}//Registering radius Dependency Properties//Radius represents the name of the Radius property//typeof (Double) indicates the type of RADIUS attribute//typeof (Circlepanel) represents the attribution type of the RADIUS attribute//New PropertyMetadata (0.0, onradiuspropertychanged)) represents a metadata instance of the RADIUS attribute, 0.0 is the default value, and Onradiuspropertychanged is the event of a property change Public Static ReadOnlyDependencyProperty Radiusproperty =dependencyproperty.registerattached ("Radius", typeof(Double), typeof(Circlepanel),NewPropertyMetadata (0.0, onradiuspropertychanged)); //Defining RADIUS Properties Public DoubleRadius {Get{return(Double) GetValue (Radiusproperty); } Set{SetValue (radiusproperty, value);} } //Implementing Radius Property Change Events Private Static voidonradiuspropertychanged (DependencyObject obj, DependencyPropertyChangedEventArgs e) {//gets the Circlepanel object that triggered the property changeCirclepanel target =(circlepanel) obj; //gets the most recent value passed in and assigns a value to the RADIUS variableTarget._radius = (Double) E.newvalue; //to invalidate the arrangement state and rearrange it.Target. Invalidatearrange (); } //MeasureOverride methods for overloading base classes protected Overridesize measureoverride (size availablesize) {//logic to process the measurement sub-object returnavailablesize; } //Arrangeoverride methods for overloading base classes protected Overridesize arrangeoverride (size finalsize) {//handle the logic of arranging child objects returnfinalsize; } }
3.2.2 Realization of measurement process
The process of measurement is implemented on overloaded MeasureOverride methods, and the first thing that needs to be done on the MeasureOverride method is to traverse all the sub-objects once, calling its measure method to measure the size of the sub-object. Then in the measurement process can get to the sub-object measurement of the width of the height, we can according to this information to customize the panel to allocate its size.
protected Overridesize measureoverride (size availablesize) {//The maximum width of the variable DoubleMaxelementwidth =0; //Traverse all sub-objects and call the measure method of the sub-object to measure and remove the maximum width of the child object foreach(UIElement Childinchchildren) { //measure sub-objectsChild . Measure (availablesize); Maxelementwidth=Math.max (child. Desiredsize.width, Maxelementwidth); } //Two the size of the radius and the maximum width of twice times the most panel width DoublePanelwidth =2* This. Radius +2*Maxelementwidth; //The actual size of the panel is the smallest value of the assigned height width and the calculated width of the panel . Doublewidth =math.min (Panelwidth, availablesize.width); DoubleHeigh =math.min (Panelwidth, availablesize.height); return NewSize (width, heigh); }
3.2.3 Implementing the arrangement process
The process of arranging is implemented on the overloaded Arrangeoverride method, and the object is arranged by the relevant rules on the Arrangeoverride method one by one. What we want to achieve in the example is that the object is arranged in a fixed circle, so the Arrangeoverride method needs to calculate the angular size of each sub-object, calculate the coordinates of the sub-object in the panel by the angle, and then rotate the child object to fit the circular layout by a certain angle. The permutation principle is shown in Figure 3.7, and the implementation code is as follows.
protected Overridesize arrangeoverride (size finalsize) {//current angle, starting from 0 Doubledegree =0; //Calculate the angle size occupied by each sub-object DoubleDegreestep = (Double) the/ This. Children.Count; //Calculation DoubleMX = This. Desiredsize.width/2; DoubleMY = This. Desiredsize.height/2; //Traverse all sub-objects to arrange foreach(UIElement Childinchchildren) { //Convert angle to Radian unit DoubleAngle = Math.PI * Degree/180.0; //calculates the coordinate value of x, Y on the arc based on radians Doublex = Math.Cos (angle) * This. _radius; Doubley = Math.sin (angle) * This. _radius; //Use the transform effect to make the control rotate the angle degreeRotateTransform RotateTransform =NewRotateTransform (); Rotatetransform.angle=degree; Rotatetransform.centerx=0; Rotatetransform.centery=0; Child. RenderTransform=RotateTransform; //Arranging child ObjectsChild. Arrange (NewRect (MX + x, MY +y, child. Desiredsize.width, child. Desiredsize.height)); //Angle Incrementdegree + =Degreestep; } returnfinalsize; }
3.2.4 Applying layout rules
We've implemented the custom circular layout control above, and now we're going to apply the layout Panel on the XAML page to lay it out. In this example, we also use a slider control to dynamically change the size of the layout panel's radius to see how the layout changes.
First we introduce the space in the XAML page where the layout panel is located, as follows:
Xmlns:local= "Clr-namespace:custompaneldemo"
The custom circular layout control is then applied on the XAML page, and the radius of the circular layout control is dynamically assigned by the valuechanged of the slider control. The code is as follows:
MainPage.xaml file Main code--------------------------------------------------------------------------------------------------------------- ---<grid x:name="Contentpanel"grid.row="1"margin="12,0,12,0"> <Grid.RowDefinitions> <rowdefinition height="Auto"/> <rowdefinition height="Auto"/> </Grid.RowDefinitions> <slider grid.row="0"Value="5"Valuechanged="slider_valuechanged_1"></Slider> <local:circlepanel x:name="Circlepanel"radius=" -"grid.row="1"Horizontalalignment="Center"Verticalalignment="Center"> <textblock>start here</textblock> <textblock>textblock1</TextBlock> <textblock>textblock2</TextBlock> <textblock>textblock3</TextBlock> <textblock>textblock4</TextBlock> <textblock>textblock5</TextBlock> <textblock>textblock6</TextBlock> <textblock>textblock7</TextBlock> </local:CirclePanel> </Grid>
MainPage.xaml.cs File main code -------------------------------------------------------------------------------- ---------------------------------- privatevoid slider_valuechanged_1 (object sender, Rangebasevaluechangedeventargs e) { ifnull) { } }
Source code Download: Http://vdisk.weibo.com/s/zt_pyrfNHoezI