Search code examples
c#wpfxamltextboxtemplatebinding

How to apply TemplateBinding to "Auto" height and width


In resource dictionary:

<Style x:Key="ControlFrame" TargetType="{x:Type TextBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Border Background="{TemplateBinding Background}" BorderThickness="2">
                    <ScrollViewer Margin="0" x:Name="PART_ContentHost" />
                    <Border.BorderBrush>
                        <VisualBrush>
                            <VisualBrush.Visual>
                                <Rectangle StrokeDashArray="8, 2" Stroke="{TemplateBinding BorderBrush}" 
                                           StrokeThickness="2"
                                           Width="{TemplateBinding Width}"
                                           Height="{TemplateBinding Height}"/>
                            </VisualBrush.Visual>
                        </VisualBrush>
                    </Border.BorderBrush>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

In C#:

TextBox textbox = new TextBox();
textbox.Width = 200;
textbox.Height = 200;
Style style = this.FindResource("ControlFrame") as Style;
textbox.Style = style;
canvas.Children.Insert(0, textbox);

I can get the dashed border properly.

enter image description here

If I wrap the Textbox into a ContentControl without giving the height and width of the Textbox like the following:

TextBox textbox = new TextBox();
Style style = this.FindResource("ControlFrame") as Style;
textbox.Style = style;
ContentControl cc = new ContentControl();
cc.Content = textbox;
cc.Height = 200;
cc.Width = 200;
canvas.Children.Insert(0, cc);

The result is missed up:

enter image description here

I guess the reason is:

In Style, I use the following to set Width and Height of the border. They rely on the TextBox's Width and Height.

Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"

If I wrap the TextBox into a ContentControl, TextBox's Width and Height are set to Auto and changed according to the ContentControl. But, the Style cannot get the exact Height and Width any more.

My question is:

Is there any way to let my Style display properly for a TextBox wrapped within a ContentControl. Since the ContentControl is draggable, I cannot set exact Height and Width to the inside TextBox.


Solution

  • If you are not explicitly setting the Width/Height, you will have to change your template bindings to ActualWidth/ActualHeight:

    <VisualBrush.Visual>
       <Rectangle StrokeDashArray="8, 2" Stroke="{TemplateBinding BorderBrush}" 
                  StrokeThickness="2"
                  Width="{TemplateBinding ActualWidth}"
                  Height="{TemplateBinding ActualHeight}"/>
    </VisualBrush.Visual>
    

    Layout:(if I understand your question correctly)

     <Grid>
         <ContentControl >
            <TextBox BorderBrush="Red" Background="Blue" Style="{StaticResource ControlFrame}" />
         </ContentControl>
     </Grid>
    

    ActualWidth/ActualHeight will return the rendered size of the control, Width/Height will returm NaN if its not explicity set elsewhere.