c# - WPF Custom GroupBox Header OpacityMask issues -


i've created custom groupbox control provides button @ top right. noticed border not provide gap button header, wrote custom bordergapconverter. works until content of header changes. border, , believe opacitymask doesn't change until window contains control resized.

buttonedgroupbox.cs

namespace my.controls {     /// <summary>     /// interaction logic buttonedgroupbox.xaml     /// </summary>     public partial class buttonedgroupbox : groupbox     {         public static readonly dependencyproperty commandproperty = dependencyproperty.register("command", typeof(icommand), typeof(buttonedgroupbox), new frameworkpropertymetadata(null));         public static readonly dependencyproperty commandparameterproperty = dependencyproperty.register("commandparameter", typeof(object), typeof(buttonedgroupbox), new frameworkpropertymetadata(null));          protected override void onheaderchanged(object oldheader, object newheader)         {             base.onheaderchanged(oldheader, newheader);             try             {                 getbindingexpression(opacitymaskproperty).updatetarget();             }             catch (nullreferenceexception) { }         }          public icommand command { { return (icommand)getvalue(commandproperty); } set { setvalue(commandproperty, value); } }         public object commandparameter { { return getvalue(commandparameterproperty); } set { setvalue(commandparameterproperty, value); } }          public buttonedgroupbox()         {             initializecomponent();         }     } } 

buttonedgroupbox.xaml

<groupbox x:class="my.controls.buttonedgroupbox" x:name="ctrlthis"           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"            xmlns:cv="clr-namespace:my.valueconverters"           mc:ignorable="d"           d:designheight="300" d:designwidth="300">     <groupbox.resources>         <bordergapmaskconverter x:key="bordergapmaskconverter"/>         <cv:bordergapconverter x:key="mybordergapmaskconverter"/>     </groupbox.resources>     <groupbox.style>         <style targettype="{x:type groupbox}">             <setter property="borderbrush" value="#d5dfe5"/>             <setter property="borderthickness" value="1"/>         </style>     </groupbox.style>     <groupbox.template>         <controltemplate targettype="{x:type groupbox}">             <grid snapstodevicepixels="true">                 <grid.columndefinitions>                     <columndefinition width="6"/>                     <columndefinition width="auto"/>                     <columndefinition width="*"/>                     <columndefinition width="auto"/>                     <columndefinition width="6"/>                 </grid.columndefinitions>                 <grid.rowdefinitions>                     <rowdefinition height="auto"/>                     <rowdefinition height="auto"/>                     <rowdefinition height="*"/>                     <rowdefinition height="6"/>                 </grid.rowdefinitions>                 <border borderbrush="transparent" borderthickness="{templatebinding borderthickness}" background="{templatebinding background}" grid.columnspan="5" grid.column="0" cornerradius="4" grid.row="1" grid.rowspan="3"/>                 <border borderbrush="white" borderthickness="{templatebinding borderthickness}" grid.columnspan="5" cornerradius="4" grid.row="1" grid.rowspan="3">                     <border.opacitymask>                         <multibinding converterparameter="6" converter="{staticresource mybordergapmaskconverter}">                             <binding relativesource="{relativesource mode=findancestor, ancestortype=grid}"/>                             <binding path="actualwidth" relativesource="{relativesource self}"/>                             <binding path="actualheight" relativesource="{relativesource self}"/>                         </multibinding>                     </border.opacitymask>                     <border borderbrush="{templatebinding borderbrush}" borderthickness="{templatebinding borderthickness}" cornerradius="3">                         <border borderbrush="white" borderthickness="{templatebinding borderthickness}" cornerradius="2"/>                     </border>                 </border>                 <border x:name="header" grid.column="1" padding="3,1,3,1" grid.row="0" grid.rowspan="2">                     <contentpresenter contentsource="header" recognizesaccesskey="true" snapstodevicepixels="{templatebinding snapstodevicepixels}"/>                 </border>                 <border grid.column="3" padding="3,1,3,1" grid.row="0" grid.rowspan="2">                     <button x:name="copybutton" content="copy" grid.column="3" grid.row="0" grid.rowspan="2" horizontalalignment="stretch" snapstodevicepixels="{templatebinding snapstodevicepixels}"                         horizontalcontentalignment="center" verticalcontentalignment="center"                         command="{binding command, elementname=ctrlthis}" commandparameter="{binding commandparameter, elementname=ctrlthis}"/>                 </border>                 <contentpresenter grid.columnspan="3" grid.column="1" margin="{templatebinding padding}" grid.row="2" snapstodevicepixels="{templatebinding snapstodevicepixels}"/>             </grid>         </controltemplate>     </groupbox.template> </groupbox> 

bordergapconverter

public class bordergapconverter : imultivalueconverter     {         public object convert(object[] values, type targettype, object parameter, system.globalization.cultureinfo culture)         {             type doubletype = typeof(double);              // data validation             if (values == null) return dependencyproperty.unsetvalue;              foreach (var value in values)             {                 type valuetype = value.gettype();                 if (value == null || (!typeof(frameworkelement).isassignablefrom(valuetype) && !doubletype.isassignablefrom(valuetype)))                      return dependencyproperty.unsetvalue;             }              type paramtype = parameter.gettype();;             if (parameter == null || (!doubletype.isassignablefrom(paramtype) && !typeof(string).isassignablefrom(paramtype))) return dependencyproperty.unsetvalue;              double offset = 0d;             if (parameter string)                 offset = double.parse((string)parameter, numberformatinfo.invariantinfo);             else                 offset = (double)parameter;              grid hostgrid = (grid)values[0];             double borderwidth = (double)values[1];             double borderheight = (double)values[2];              if (borderwidth == 0d || borderheight == 0d) return null;              // create 5x2 grid             grid grid = new grid() { width = borderwidth, height = borderheight };             foreach(columndefinition col in hostgrid.columndefinitions)                 grid.columndefinitions.add(new columndefinition() { width = new gridlength(col.actualwidth) });              // define rows             grid.rowdefinitions.add(new rowdefinition() { height = new gridlength(borderheight / 2d) });             grid.rowdefinitions.add(new rowdefinition() { height = new gridlength(1d, gridunittype.star) });              /**              * cartesian coordinates              * - 0 1 2              * 0|-|-|-|              * 1|-|-|-|              */             // set rectangle 1 0, 0 0, 1             rectangle rectangle = new rectangle() { fill = brushes.black };             grid.setrowspan(rectangle, 2);             grid.setrow(rectangle, 0);             grid.setcolumn(rectangle, 0);              // set rectangle2 1, 1             rectangle rectangle2 = new rectangle() { fill = brushes.black };             grid.setrow(rectangle2, 1);             grid.setcolumn(rectangle2, 1);              // set rectangle3 0, 2 1, 2             rectangle rectangle3 = new rectangle() { fill = brushes.black };             grid.setrowspan(rectangle3, 2);             grid.setrow(rectangle3, 0);             grid.setcolumn(rectangle3, 2);              // set rectangle4 0, 2 1, 2             rectangle rectangle4 = new rectangle() { fill = brushes.black };             grid.setrow(rectangle4, 1);             grid.setcolumn(rectangle4, 3);              // set rectangle3 0, 2 1, 2             rectangle rectangle5 = new rectangle() { fill = brushes.black };             grid.setrowspan(rectangle5, 2);             grid.setrow(rectangle5, 0);             grid.setcolumn(rectangle5, 4);              grid.children.add(rectangle);             grid.children.add(rectangle2);             grid.children.add(rectangle3);             grid.children.add(rectangle4);             grid.children.add(rectangle5);             return new visualbrush(grid);         }          public object[] convertback(object value, type[] targettypes, object parameter, system.globalization.cultureinfo culture)         {             return new object[] { binding.donothing };         }     } 

i've tried override metadata on headerproperty, override onheaderchanged, changed using headertemplate, , bound header , set headerstringformat no avail.

here how i'm using control:

        <ctrl:buttonedgroupbox command="{binding copycontentscommand}" header="{binding dynamictitle}" headerstringformat="static - {0}">             <textblock>                 lorem ipsum sit dolorem             </textblock>         </ctrl:buttonedgroupbox> 

how opacitymask update when header's underlying textblock changes?

edit

so added header element's actualwidth multibinding, works seems unnecessary.

<multibinding converterparameter="6" converter="{staticresource mybordergapmaskconverter}">                                         <binding relativesource="{relativesource mode=findancestor, ancestortype=grid}"/>                                         <binding path="actualwidth" relativesource="{relativesource self}"/>                                         <binding path="actualheight" relativesource="{relativesource self}"/>                                         <binding elementname="header" path="actualwidth"/>                                     </multibinding> 


Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -