Reputation: 34293
A website can be designed to adapt to smaller screen sizes using media queries. For example, three columns on a wide screen, one column on a low-resolution phone.
Is there a similar technique for WPF to adjust the layout based on available screen space or parent control size?
For example, I'd like to have 3 columns displayed horizontally on a large screen, but displayed vertically on smaller screen. Ideally, I'd like to formulate layouts like this: "If this control's width is less than 400 points, rearrange these controls in that way."
How can I create an adaptive design like this in WPF? That is, define different layouts for controls for specific parent control sizes?
Ideally controls should be rearranged instead of duplicated or recreated, to avoid being extremely slow.
Upvotes: 11
Views: 10912
Reputation: 311335
If you're using the UWP flavour of WPF, then you might use AdaptiveTrigger
:
<AdaptiveTrigger MinWindowWidth="720" MinWindowHeight="900" />
Upvotes: 3
Reputation: 132648
The easiest way to do this is with DataTriggers
and a Converter
to test if the bound value is greater or less than a parameter.
This will allow you to easily adjust the style setters based on a bound value. For example, you could use
<Style x:Key="MyControlStyle">
<!-- Default Values -->
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Grid.Column" Value="0" />
<Style.Triggers>
<DataTrigger Value="True"
Binding="{Binding ActualHeight, ElementName=MyWindow,
Converter={StaticResource IsValueLessThanParameter},
ConverterParameter=400}">
<!-- Values to use when Trigger condition is met -->
<Setter Property="Grid.Row" Value="1" />
<Setter Property="Grid.Column" Value="1" />
</DataTrigger>
</Style.Triggers>
</Style>
In the case where you have a more complex layout with many pieces that change based on some triggered value, you can replace entire Templates with your trigger instead of just individual properties
<Style x:Key="MyContentControlStyle" TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource BigTemplate}" />
<Style.Triggers>
<DataTrigger Value="True"
Binding="{Binding ActualHeight, ElementName=MyWindow,
Converter={StaticResource IsValueLessThanParameter},
ConverterParameter=400}">
<Setter Property="ContentTemplate" Value="{StaticResource LittleTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
I believe you can also bind to the SystemParameters
object to use additional information about the application in your bindings, although I can't remember the exact syntax for it right now.
Upvotes: 20
Reputation: 7204
The only way I know to do something like this is in code, and you'll need to create a custom layout. The simplest way of doing that is to create a new class that inherits from Panel, and implement MeasureOverride and ArrangeOverride. I've done custom layouts before, and they can end up being a rather large pain to get working for all cases. If you Google "wpf custom layout" you'll get some good examples to start with. Given all the functionality you want, you'll definitely have your work cut out for you. You'll probably want to look at attached properties to see about putting annotations in the xaml to give your code an idea of what should be included at the different sizes.
Upvotes: 1