wpf - Targeting nested content in Xaml displayed using ContentPresenter -


consider following usercontrol:

filter pane control

this custom usercontrol have written has 2 nested elements.

filtercontent displays special type of markup filters content on right hand side of screen

maincontent hosts filtered content.

the real purpose of control provide consistent ui , animation across application, filter/content pattern used frequently.

the (simplified) xaml of usercontrol follows:

<usercontrol>     <grid>         <grid.columndefinitions>             <columndefinition width="3*"/>             <columndefinition width="7*"/>         </grid.columndefinitions>         <contentpresenter grid.column="0"  content="{binding elementname=filtercontrol, path=filtercontrol}" datacontext="{binding}" />         <contentpresenter grid.column="1"  content="{binding elementname=filtercontrol, path=maincontrol}" datacontext="{binding}" />     </grid> 

the codebehind :

public sealed partial class filterpanecontrol : usercontrol {     public static dependencyproperty filtercontrolproperty = dependencyproperty.register("filtercontrol", typeof(object), typeof(filterpanecontrol), new propertymetadata(default(object), propertychangedcallback));      public static dependencyproperty maincontrolproperty = dependencyproperty.register("maincontrol", typeof (object), typeof (filterpanecontrol), new propertymetadata(default(object)));      public filterpanecontrol()     {         this.initializecomponent();     }      public object filtercontrol     {         { return (object)getvalue(filtercontrolproperty); }         set { setvalue(filtercontrolproperty, value); }     }      public object maincontrol     {         { return (object) getvalue(maincontrolproperty); }         set { setvalue(maincontrolproperty, value); }     } } 

the usage of control in implementing page :

    <generic:filterpanecontrol>         <generic:filterpanecontrol.filtercontrol>             <grid>                 <textblock text="filter content here"/>             </grid>         </generic:filterpanecontrol.filtercontrol>         <generic:filterpanecontrol.maincontrol>             <grid>                 <textblock text="main content here"/>             </grid>         </generic:filterpanecontrol.maincontrol>     </generic:filterpanecontrol> 

that works fine!

the problem

the problem when want reference of content within control implementing page. case visual states handling snap/portrait (winrt implementation)

enter image description here

    <generic:filterpanecontrol>         <generic:filterpanecontrol.filtercontrol>             <grid>                 <textblock x:name="filtercontent1"  text="filter content here"/>             </grid>         </generic:filterpanecontrol.filtercontrol>         <generic:filterpanecontrol.maincontrol>             <grid>                 <textblock text="main content here"/>             </grid>         </generic:filterpanecontrol.maincontrol>     </generic:filterpanecontrol>      <visualstatemanager.visualstategroups>         <visualstate x:name="fullscreenportrait">             <storyboard>                 <objectanimationusingkeyframes storyboard.targetname="filtercontent1" storyboard.targetproperty="width">                     <discreteobjectkeyframe keytime="0" value="200"/>                 </objectanimationusingkeyframes>             </storyboard>         </visualstate>     </visualstatemanager.visualstategroups> 

this leads run-time exception, visualstatemanager cannot find referenced element 'filtercontent1' though exists in visual tree. additionally, if try , reference element directly in page.loaded event handler, filtercontent1 null.

it if nested xaml doesn't render until later - throwing visualstatemanager too.

any suggestions?

first, visualstatemanager should placed in single panel element done, otherwise exception. case turns out this:

<generic:filterpanecontrol>     <generic:filterpanecontrol.filtercontrol>         <grid>             <visualstatemanager.visualstategroups>                 <visualstate x:name="fullscreenportrait">                     <storyboard>                         <objectanimationusingkeyframes storyboard.targetname="filtercontent1" storyboard.targetproperty="width">                             <discreteobjectkeyframe keytime="0" value="200"/>                         </objectanimationusingkeyframes>                     </storyboard>                 </visualstate>             </visualstatemanager.visualstategroups>              <textblock x:name="filtercontent1" text="filter content here"/>         </grid>     </generic:filterpanecontrol.filtercontrol>      ... 

second, visualstatemanager placed in either template / style, or usercontrol. transition states carried out either in code or through xaml (with special techniques). sample of set state behind code:

visualstatemanager.gotostate(nameofcontrol, "state1", true); 

third, in manner:

<storyboard>      <objectanimationusingkeyframes storyboard.targetname="filtercontent1" storyboard.targetproperty="width">            <discreteobjectkeyframe keytime="0" value="200"/>      </objectanimationusingkeyframes> </storyboard> 

width not sets, in case exception. need use animation this:

<storyboard storyboard.targetname="filtercontent1" storyboard.targetproperty="width">     <doubleanimation to="200" duration="0:0:1.0"/> </storyboard> 

as proof of words, give example:

mainwindow

<window x:class="vsminusercontrolhelp.mainwindow"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"             xmlns:local="clr-namespace:vsminusercontrolhelp"     title="mainwindow" height="350" width="525"     windowstartuplocation="centerscreen">      <grid>         <grid.rowdefinitions>             <rowdefinition/>             <rowdefinition height="40"/>         </grid.rowdefinitions>          <local:usercontrol1 x:name="control1" height="118" verticalalignment="top" margin="50,12,101,0" />          <stackpanel orientation="horizontal" grid.row="1">             <button name="state1button" width="75" click="state1button_click">state1</button>         </stackpanel>     </grid> </window> 

code behind

public partial class mainwindow : window {     public mainwindow()     {         initializecomponent();             }      private void state1button_click(object sender, routedeventargs e)     {         visualstatemanager.gotostate(control1, "state1", true);     } } 

usercontrol

<usercontrol x:class="vsminusercontrolhelp.usercontrol1"          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:sys="clr-namespace:system;assembly=mscorlib"          mc:ignorable="d"                        d:designheight="300" d:designwidth="300">      <grid>         <visualstatemanager.visualstategroups>             <visualstategroup x:name="common1">                 <visualstate x:name="state1">                     <storyboard storyboard.targetname="filtercontent1" storyboard.targetproperty="width">                         <doubleanimation to="200" duration="0:0:1.0"/>                     </storyboard>                 </visualstate>             </visualstategroup>         </visualstatemanager.visualstategroups>          <textblock x:name="filtercontent1" background="aqua" width="100" horizontalalignment="left" text="filter content here"/>     </grid> </usercontrol> 

note: example run on vs 2010, windows xp, not tested under winrt.


Comments