c# - How to achieve even horizontal spacing in ListView and WrapPanel template? -


heres example:

<window x:class="listviewitemspacing.mainwindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"         xmlns:c="clr-namespace:listviewitemspacing.controls"         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"         xmlns:local="clr-namespace:listviewitemspacing"         mc:ignorable="d"         title="mainwindow" height="350" width="525">     <grid>         <listview flowdirection="lefttoright" background="#222">             <listview.itemspanel>                 <itemspaneltemplate>                     <wrappanel width="{binding (frameworkelement.actualwidth), relativesource={relativesource ancestortype=scrollcontentpresenter}}" />                 </itemspaneltemplate>             </listview.itemspanel>             <listview.items>                 <rectangle fill="#27f" width="100" height="100"/>                 <rectangle fill="#27f" width="100" height="100"/>                 <rectangle fill="#27f" width="100" height="100"/>                 <rectangle fill="#27f" width="100" height="100"/>                 <rectangle fill="#27f" width="100" height="100"/>                 <rectangle fill="#27f" width="100" height="100"/>             </listview.items>         </listview>     </grid> </window> 

this xaml produces 6 blue squares, 4 in first row, 2 in next row. after 4 first blue squares there space on right.

in other words - looks left aligned text.

i want justified text, want horizontal spacing between squares adjusted align listview left , right, space evenly distributed between elements, not on right side.

although looks trivial do, don't know how it. don't know start. example - can see spacing added default. ugly default, because horizontal spacing greater vertical, it's not big enough align items both left , right side. spacing come from? how change manually? don't want mess elements themselves. elements in real world app come different module , modules should separated.

most obvious thought handle sizechanged event of listview , adjust horizontal spacing manually, - spacing? mean how can access items spacing in code behind?

to clarify: desired rendering should still contain 6 identical blue squares, first 4 aligned left , right control edge, remaining 2 aligned left , previous row squares.

default this:

---------------- |[] [] [] []   |  |[] []         | ---------------- 

desired this:

---------------- |[]  []  []  []|  |[]  []        | ---------------- 

thanks rachel , dtig made it. seems there's no panel capable of aligning elements wrappanel customizable horizontalcontentalignment. , - horizontalcontentalignment = horizontalalignment.stretch needed here.

following rachel advice tried this, didn't support horizontalalignment.stretch value.

so added support, works provided element widths equal each other:

/// <summary> /// <see cref="panel"/> <see cref="wrappanel"/> supports <see cref="horizontalcontentalignment"/> property. /// </summary> public class alignablewrappanel : panel {      /// <summary>     /// <see cref="horizontalalignment"/> property definition.     /// </summary>     public static readonly dependencyproperty horizontalcontentalignmentproperty =         dependencyproperty.register(             "horizontalcontentalignment",             typeof(horizontalalignment),             typeof(alignablewrappanel),             new frameworkpropertymetadata(horizontalalignment.left, frameworkpropertymetadataoptions.affectsarrange)         );      /// <summary>     /// gets or sets horizontal alignment of control's content.     /// </summary>     [bindableattribute(true)]     public horizontalalignment horizontalcontentalignment {         { return (horizontalalignment)getvalue(horizontalcontentalignmentproperty); }         set { setvalue(horizontalcontentalignmentproperty, value); }     }      /// <summary>     /// measures size in layout required child elements , determines size <see cref="alignablewrappanel"/>.     /// </summary>     /// <param name="constraint">the available size element can give child elements. infinity can specified value indicate element size whatever content available.</param>     /// <returns>the size element determines needs during layout, based on calculations of child element sizes.</returns>     protected override size measureoverride(size constraint) {         var curlinesize = new size();         var panelsize = new size();         var children = base.internalchildren;         (var = 0; < children.count; i++) {             var child = children[i] uielement;             // flow passes own constraint children             child.measure(constraint);             var sz = child.desiredsize;             if (curlinesize.width + sz.width > constraint.width) { //need switch line                 panelsize.width = math.max(curlinesize.width, panelsize.width);                 panelsize.height += curlinesize.height;                 curlinesize = sz;                 if (sz.width > constraint.width) { // if element wider constraint - give separate line                                         panelsize.width = math.max(sz.width, panelsize.width);                     panelsize.height += sz.height;                     curlinesize = new size();                 }             }             else { //continue accumulate line                 curlinesize.width += sz.width;                 curlinesize.height = math.max(sz.height, curlinesize.height);             }         }         // last line size, if need added         panelsize.width = math.max(curlinesize.width, panelsize.width);         panelsize.height += curlinesize.height;         return panelsize;     }      /// <summary>     /// positions child elements , determines size <see cref="alignablewrappanel"/>.     /// </summary>     /// <param name="arrangebounds">the final area within parent element should use arrange , children.</param>     /// <returns>the actual size used.</returns>     protected override size arrangeoverride(size arrangebounds) {         var firstinline = 0;         var curlinesize = new size();         var accumulatedheight = 0.0;         var children = internalchildren;         (var = 0; < children.count; i++) {             var sz = children[i].desiredsize;             if (curlinesize.width + sz.width > arrangebounds.width) { //need switch line                 arrangeline(accumulatedheight, curlinesize, arrangebounds.width, firstinline, i);                 accumulatedheight += curlinesize.height;                 curlinesize = sz;                 if (sz.width > arrangebounds.width) { //the element wider constraint - give separate line                                         arrangeline(accumulatedheight, sz, arrangebounds.width, i, ++i);                     accumulatedheight += sz.height;                     curlinesize = new size();                 }                 firstinline = i;             }             else { //continue accumulate line                 curlinesize.width += sz.width;                 curlinesize.height = math.max(sz.height, curlinesize.height);             }         }         if (firstinline < children.count)             arrangeline(accumulatedheight, curlinesize, arrangebounds.width, firstinline, children.count);         return arrangebounds;     }      /// <summary>     /// arranges elements within line.     /// </summary>     /// <param name="y">line vertical coordinate.</param>     /// <param name="linesize">size of items line.</param>     /// <param name="boundswidth">width of panel bounds.</param>     /// <param name="start">index of first child belongs line.</param>     /// <param name="end">index of last child belongs line.</param>     private void arrangeline(double y, size linesize, double boundswidth, int start, int end) {         var children = internalchildren;         var x = 0.0;         var stretchoffset = 0.0;         if (horizontalcontentalignment == horizontalalignment.center) x = (boundswidth - linesize.width) / 2;         else if (horizontalcontentalignment == horizontalalignment.right) x = (boundswidth - linesize.width);         else if (horizontalalignment == horizontalalignment.stretch) {             var childwidth = children[start].desiredsize.width; // warning, works when children have equal widths             int n = (int)boundswidth / (int)childwidth;             if (children.count > n) {                 var takenwidth = n * childwidth;                 var spacewidth = boundswidth - takenwidth;                 stretchoffset = spacewidth / (n - 1);             }         }         (var = start; < end; i++) {             var child = children[i];             child.arrange(new rect(x, y, child.desiredsize.width, linesize.height));             x += child.desiredsize.width + stretchoffset;         }     }  } 

this tig's solution stretch alignment added.

here's test xaml this:

<window     x:class="listviewitemspacing.mainwindow"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:c="clr-namespace:customcontrols"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:local="clr-namespace:listviewitemspacing"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     title="mainwindow"     width="525"     height="250"     mc:ignorable="d">     <grid>         <listview background="#222">             <listview.itemspanel>                 <itemspaneltemplate>                     <c:alignablewrappanel width="{binding (frameworkelement.actualwidth), relativesource={relativesource ancestortype=scrollcontentpresenter}}" horizontalcontentalignment="stretch" />                 </itemspaneltemplate>             </listview.itemspanel>             <listview.items>                 <rectangle                     width="100"                     height="100"                     fill="#27f" />                 <rectangle                     width="100"                     height="100"                     fill="#27f" />                 <rectangle                     width="100"                     height="100"                     fill="#27f" />                 <rectangle                     width="100"                     height="100"                     fill="#27f" />                 <rectangle                     width="100"                     height="100"                     fill="#27f" />                 <rectangle                     width="100"                     height="100"                     fill="#27f" />             </listview.items>         </listview>     </grid> </window> 

it's not perfect, specific job perfectly. won't work if sizes of child elements different - in such case takenwidth should calculated sum of children indices start end. should specify different condition last line.

thanks again, kind strangers :)


Comments

Popular posts from this blog

angular - Is it possible to get native element for formControl? -

unity3d - Rotate an object to face an opposite direction -

javascript - Why jQuery Select box change event is now working? -