问题
I am trying to have a simple header of the page "adaptively" change the padding value based off of the width of the Page. Namely I have a header TextBlock using a style from a Resource Dictionary as shown below:
<Style x:Key="PageHeaderStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="16" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
In my page now I have a simple TextBlock that uses the Style from the Resource Dictionary above. In the page if I use the following code my adaptive triggers as shown below everything works:
<Page
...
Style="{StaticResource PageStyle}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PageHeader.Padding" Value="48,0,0,0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Compact">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PageHeader.Padding" Value="0,0,0,0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Wide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1024"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PageHeader.Padding" Value="0,0,0,0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="{StaticResource GridHamburgerHeight}"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="14"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{x:Bind Path=helper:CommonStyles.HamburgerPaneBackgroundColour}" Grid.Row="0" Grid.ColumnSpan="2"/>
<TextBlock Style="{StaticResource PageHeaderStyle}" Grid.Column="1" Text="HOME"/>
</Grid>
</Page>
My question is, how can I move that Adaptive VisualStateManager piece into the Style object within the Resource Dictionary itself so that I can re-use this header style and its "adaptive-ness" without having to paste the VisualStateManager on each page.
Thanks!
回答1:
As I've tried it's not possible to change page's template, seems to always use a default one. Therefore, taking into account that VisualStateManager must be in the root element of a Control - source at MSDN:
Control authors or app developers add VisualStateGroup object elements to the root element of a control template definition in XAML, using the VisualStateManager.VisualStateGroups attached property.
you will probably have to create a custom UserControl or extend Page class - there you can add VisualStateManager and you won't have to repeat it all over, just use that control/page.
This is very simple example and should be extended, but it will give you a point to start (the source code you can check at Github. For your case I would create a TemplatedControl - right click on your project in solution manager, then Add->New Item, then select Templated Control, lets name it AdaptiveTriggerControl, this should create a cs file and a Generic.xaml in Themes folder. Open the AdaptiveTriggerControl.cs file and modify the class it derives from - change from Control
to ContentControl
:
public sealed class AdaptiveTriggerControl : ContentControl
In Generic.xaml you define the control:
<Style TargetType="local:AdaptiveTriggerControl" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:AdaptiveTriggerControl">
<Border x:Name="MyBorder"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<!--Background="{TemplateBinding Background}"-->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyBorder.Background" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Compact">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyBorder.Background" Value="Green"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Wide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1024"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyBorder.Background" Value="Blue"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then you can use it simply like this:
<local:AdaptiveTriggerControl>
<TextBlock Text="Content of your page"/>
</local:AdaptiveTriggerControl>
More information about TemplatedControls, a sample of creating UserControl.
来源:https://stackoverflow.com/questions/42614367/adaptive-triggers-in-resource-dictionary