Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to use a xaml trigger or styleselector to adjust size of control based upon available space
    text
    copied!<p>I'm trying to make a button that is styled to change its layout to make itself smaller based upon how much space is available.</p> <p>These buttons will always have a stackpanel with an image and a textblock within it. I'm aiming to be able to define 3-4 different styles for these buttons, each resulting in a different button size.</p> <p>For each button image, I have 4 versions if the image in different resolutions. 16, 32, 48 and 64. These images are stored in different folders; i.e. Images\Icons\16\Add.png and Images\Icons\32\Add.png. Both of those images are the same, just different sizes. I've chosen to use multiple sizes because I found that just having one image and scaling its size caused it to be rather blurry.</p> <p>To facilitate choosing different sized images, I've created a converter which I use when binding the image source:</p> <pre><code>class ImagePathResolutionConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Image sender = (Image)value; int imageSize = (parameter != null) ? (parameter is int) ? (int)parameter : (parameter is string) ? Int32.Parse((string)parameter) : 16 : 16; Uri returnImage = new Uri(String.Format(@"Images\Icons\{0}\{1}", imageSize, sender.Tag as string), UriKind.Relative); return returnImage; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } </code></pre> <p>The binding looks like this:</p> <pre><code>&lt;Setter Property="Source" Value="{Binding ., Converter={StaticResource ImagePathResolutionConverter}, RelativeSource={RelativeSource Self}, ConverterParameter='16'}" /&gt; </code></pre> <p>Using this set up means that I can pass 16, 32, 48 or 64 to the ConverterParameter, and the appropriate image path will be returned.</p> <p>Now, for this example, I have two styles;</p> <p>Big:</p> <pre><code>&lt;!-- Big Button Container Style --&gt; &lt;Style TargetType="Button" x:Key="MultiResButton_Big"&gt; &lt;Setter Property="HorizontalAlignment" Value="Left" /&gt; &lt;Setter Property="VerticalAlignment" Value="Top" /&gt; &lt;Style.Resources&gt; &lt;!-- Button.StackPanel Style --&gt; &lt;Style TargetType="StackPanel"&gt; &lt;Setter Property="Orientation" Value="Vertical" /&gt; &lt;Style.Resources&gt; &lt;!-- Button.StackPanel.Image Style --&gt; &lt;Style TargetType="Image"&gt; &lt;Setter Property="Stretch" Value="None" /&gt; &lt;Setter Property="Margin" Value="5 2 5 0" /&gt; &lt;Setter Property="Source" Value="{Binding ., Converter={StaticResource ImagePathResolutionConverter}, RelativeSource={RelativeSource Self}, ConverterParameter='32'}" /&gt; &lt;/Style&gt; &lt;!-- Button.StackPanel.TextBlock Style --&gt; &lt;Style TargetType="TextBlock"&gt; &lt;Setter Property="Margin" Value="5 0 5 2" /&gt; &lt;/Style&gt; &lt;/Style.Resources&gt; &lt;/Style&gt; &lt;/Style.Resources&gt; &lt;/Style&gt; </code></pre> <p>... and Small</p> <pre><code>&lt;!-- Small Button Container Style --&gt; &lt;Style TargetType="Button" x:Key="MultiResButton_Small"&gt; &lt;Setter Property="HorizontalAlignment" Value="Left" /&gt; &lt;Setter Property="VerticalAlignment" Value="Top" /&gt; &lt;Style.Resources&gt; &lt;!-- Button.StackPanel Style --&gt; &lt;Style TargetType="StackPanel"&gt; &lt;Setter Property="Orientation" Value="Horizontal" /&gt; &lt;Style.Resources&gt; &lt;!-- Button.StackPanel.Image Style --&gt; &lt;Style TargetType="Image"&gt; &lt;Setter Property="Stretch" Value="None" /&gt; &lt;Setter Property="Margin" Value="5 2" /&gt; &lt;Setter Property="Source" Value="{Binding ., Converter={StaticResource ImagePathResolutionConverter}, RelativeSource={RelativeSource Self}, ConverterParameter='16'}" /&gt; &lt;/Style&gt; &lt;!-- Button.StackPanel.TextBlock Style --&gt; &lt;Style TargetType="TextBlock"&gt; &lt;Setter Property="Margin" Value="0 5 2 5" /&gt; &lt;/Style&gt; &lt;/Style.Resources&gt; &lt;/Style&gt; &lt;/Style.Resources&gt; &lt;/Style&gt; </code></pre> <p>The XAML for one of these buttons is :</p> <pre><code>&lt;Button Style="{StaticResource ResourceKey=MultiResButton_Big}"&gt; &lt;StackPanel&gt; &lt;Image Tag="Multi.png" /&gt; &lt;TextBlock Text="Button Text" /&gt; &lt;/StackPanel&gt; &lt;/Button&gt; </code></pre> <p>At the moment, I can set a button to either or these, and the results are a big or small button. Now I just need to work out how to determin when to use which, and how to do so programatically.</p> <p>The way I see it, I have two options: Combine both styles into one and use a trigger of some sort, OR create a styleSelector class and let it choose which style to use.</p> <p>My problem is that I'm at a loss as to how to programatically determine which style to use. I've found the 'RenderSize.Width' gets set to 0 when the button is pushed beyond the visible range of the container. My issue is that when 5 buttons are outside the visible bounds of the container, setting the 5 to use the smaller style won't help... I'll have to also use the smaller size for other visible buttons in order to 'make room' for the 5 that are outside the bounds.</p> <p>I'd be happy with setting the style for all buttons within a container... the moment one buttons renderSize.Width = 0, knock all of the sibling buttons down to on style size lower...</p> <p>Is what I'm attempting even possible? Would I have to create a custom container in order to override the rendering of all of the child controls? I would rather avoid that if I can... but I can't see any other possible way...</p> <p>As an example of what I'm trying to accomplish, open Word or Excel 2007/2010, and slowly resize the window to make it smaller. As you so so, the buttons in the ribon 'shrink' to make more room.</p> <p>I would appreciate any thoughts on whether I'm approaching this from the right direction.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload