title: How to use a xaml trigger or styleselector to adjust size of control based upon available space
body: <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>