lundi 29 juin 2015

WPF How to make a Viewbox aware of its available space from within a StackPanel

I have a custom WPF control based on Soroosh Davaee’s ImageButton example at http://ift.tt/T2BK1s. The custom control combines an Image and TextBlock in a horizontal StackPanel within a Button. (BTW, to get Soroosh’s example to run, I had to edit the solution properties so that “SampleView” is the startup project rather than “ExtendedButton” being the startup project.)

I want the text in the TextBlock to automatically shrink if necessary to avoid clipping at the right edge if the text is too long to fit naturally in the button. For example, if I edit Soroosh's MainWindow.xaml to make the button text too long to fit...

    ...
    <EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
    ...
    <EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
    ...

...the result is the following buttons with clipped text:

Buttons with clipped text

In researching this, it seems the simplest way to auto-shrink the content of a TextBlock is to wrap it within a Viewbox:

<Viewbox StretchDirection="DownOnly" Stretch="Fill">
    <TextBlock ... />
</Viewbox>

DownOnly apparently prevents the Viewbox from enlarging the text to fill the space, and Fill (as opposed to Uniform) seems to tell it to stretch (shrink) only the dimension that needs to shrink (i.e. the horizontal dimension in my case).

In Soroosh's example Generic.xaml file, I wrapped the TextBlock in such a Viewbox:

     <Button >
         <StackPanel Orientation="Horizontal">
             <Image Margin="2 0"
                    Source="{TemplateBinding Image}"
                    Width="{TemplateBinding ImageWidth}"
                    Height="{TemplateBinding ImageHeight}"
                    Visibility="{TemplateBinding Image,Converter={StaticResource VisibilityConvertor}}"
                    VerticalAlignment="Center"/>
I added-->   <Viewbox StretchDirection="DownOnly" Stretch="Fill">
             <TextBlock Text="{TemplateBinding Content}"
                    VerticalAlignment="Center"/>
I added-->   </Viewbox>
         </StackPanel>
     </Button>

This produced exactly the same clipped button text. Just experimenting, I tried forcing the Viewbox to have a fixed width...

             <Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">

...which produced this:

Viewbox with manually-sized width

...which shows the capability of the Viewbox, if only it could somehow know its available width when it's inside the StackPanel.

I did note that if I wrap the Viewbox around the whole StackPanel, it successfully auto-shrinks the entire content of the StackPanel:

     <Button >
         <Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">
             <StackPanel Orientation="Horizontal">
                 <Image Margin="2 0"
                    Source="{TemplateBinding Image}"
                    Width="{TemplateBinding ImageWidth}"
                    Height="{TemplateBinding ImageHeight}"
                    Visibility="{TemplateBinding Image,Converter={StaticResource VisibilityConvertor}}"
                    VerticalAlignment="Center"/>
                 <TextBlock Text="{TemplateBinding Content}"
                    VerticalAlignment="Center"/>
             </StackPanel>
         </Viewbox>
     </Button>

...which produces very nearly what I want:

Viewbox wrapping the entire StackPanel

...but both the image and text are shrunk, and I want only the text shrunk.

How can I make the Viewbox, wrapping only the TextBox, know its available width (and height, I suppose) from within a cell of the StackPanel?

Aucun commentaire:

Enregistrer un commentaire