"dynamic path icon buttons in a collection itemtemplate resource w/ mouseover" Code Answer


ok, so after you updated your question and we figured out that your culprit was the usage of menuitem and it's inherited control template giving the #ddd gray color on highlight we talked about some quick refactoring for better practices. so here's an example of what i was talking about (that you'll probably want to tweak a little to fit your needs) and assumes that your "imageaddress" is just pointed at geometry path data to create your icons.

however if that's not the case, and you're literally using images that's fine too, just swap the path object in the button template with image or whatever you want to do. so anyway here's what i do with a quick example starting with the resources you'd plop in a resource dict or wherever;

        <!-- the "icons" -->
        <geometry x:key="exampleicon">m78,63 l69.333333,75 54.00093,76.333333 67.333747,89.000655 64.667184,101.66764 78.666641,93.667175 89.332417,102.33399 90.66603,89.667334 103.33171,77.00035 86.666127,75.666984 z</geometry>
        <geometry x:key="exampleicon2">m72,62 l48,83 69,106 92,87 z</geometry>

        <!-- the button template -->
        <style x:key="neatobuttonstyle" targettype="{x:type button}">
            <setter property="overridesdefaultstyle" value="true"/>
            <setter property="background" value="transparent"/>
            <setter property="borderbrush" value="transparent"/>
            <setter property="foreground" value="white"/>
            <setter property="borderthickness" value="3"/>
            <setter property="horizontalcontentalignment" value="center"/>
            <setter property="verticalcontentalignment" value="center"/>
            <setter property="padding" value="4,2"/>
            <setter property="cursor" value="hand"/>
            <setter property="template">
                    <controltemplate targettype="{x:type button}">                      

                                    <rowdefinition height="auto"/>

                                <border grid.rowspan="2"
                                        borderbrush="{templatebinding borderbrush}" 
                                        borderthickness="{templatebinding borderthickness}" 
                                        background="{templatebinding background}" 

                                <path stretch="uniform"
                                      data="{templatebinding tag}"
                                      margin="{templatebinding padding}"/>

                                <contentpresenter grid.row="1"
                                                  margin="{templatebinding padding}" 
                                                  snapstodevicepixels="{templatebinding snapstodevicepixels}"
                                                  horizontalalignment="{templatebinding horizontalcontentalignment}"
                                                  verticalalignment="{templatebinding verticalcontentalignment}"/>



                            <trigger property="ismouseover" value="true">
                                <setter property="background" targetname="border" 
                                <setter property="borderbrush" targetname="border" 
                                <setter property="textelement.foreground" targetname="contentpresenter" 



so you'll notice i took everything you had separated out and it now all lives in one template you can use from anywhere. there's also a couple example (albeit shotty quick little drawings lol) icon example path data in there at the top. so say we have buttons we need to make now. well you just invoke what icon you want via the handy dandy tag property at the instance like;

<stackpanel orientation="horizontal" 
    horizontalalignment="center" verticalalignment="center">

        <button content="blah blah"
                style="{staticresource neatobuttonstyle}"
                tag="{staticresource exampleicon}"/>

        <button content="blah blah"
                style="{staticresource neatobuttonstyle}"
                tag="{staticresource exampleicon2}"/>


which allows a quick, easy, and manageable way to store your icons, use them as needed etc. i'd recommend setting a default for tag in the template via a setter like; <setter property="tag" value="{staticresource defaulticonresourcename}"/> just so if someone forgets to set one, you have one there.

so now we have our button setup, but how do you use it in your instance of creating them via collection? well we just swap your current itemtemplate with something like;


      <button content="{binding description}"                 
              tag="{binding imageaddress}"
              style="{staticresource neatobuttonstyle}"/>


which, in doing so eliminates a bunch of unnecessary clutter, as well as removes all those unnecessary dom elements created for each instance by using the other nested templated controls.

that's it, you're done. now if say you use the buttons all over the place and someone decides something needs tweaked, you do it in one spot and it gets inherited to every instance. as well as allowing some more flexibility for one-off scenarios where you maybe need to change other stuff easily.

anyway hope this helps. cheers!


if you wanted to add something like say a "hover state" to the path you would just add a name to your path inside the button template like;

<path x:name="buttonicon"
      data="{templatebinding tag}"
      margin="{templatebinding padding}"/>

then just add a trigger for it to the existing ismouseover ones already sitting in the button template like for example;

<setter property="fill" 

addendum to the addendum:

so to add a disabled state we just add another trigger to handle it for us and give the visual of being disabled. so we would add another trigger like this into template right where we're handling ismouseover already.

<trigger property="isenabled" value="false">
   <setter targetname="border" 
           value="{staticresource disabledbackgroundbrush}" />
   <setter targetname="border" 
           value="{staticresource disabledborderbrush}" />
   <setter property="foreground" 
           value="{staticresource disabledforegroundbrush}"/>

so now when isenabled=false our border and our foreground reflect that state by using the default disabled brushes while in that state.

keep in mind it's still a button control and comes with all the built in functionality of any standard default button. we just didn't cover all the bases for the sake of this example.

so if you need isenabled, iskeyboardfocused, ispressed etc, you can just add whatever you need in there form.

By Gareth Pulham on August 18 2022

Answers related to “dynamic path icon buttons in a collection itemtemplate resource w/ mouseover”

Only authorized users can answer the Search term. Please sign in first, or register a free account.