Amb*_*buj 2 visualstatemanager windows-store windows-store-apps
我正在制作一个Win Store应用程序,并面临处理方向的问题.
有一个网格,我想在方向改变时修改它的设计.两侧的堆叠面板(在横向视图中)应在纵向视图中转到顶部和底部.
目前,我已经使用所有控件创建了两个网格,并根据方向调整它们,并使用VisualStateManager切换可见性属性.
但是我想用一个网格实现这个目标,任何建议对我都有很大的帮助.
下图是应用程序的概念设计:

使用单个网格执行此操作很困难,但可能.
首先,您可能想要做的是减少对方向的担忧,而不是担心水平宽度.这样,如果用户以没有太多水平空间(类似于纵向模式)的方式快照应用程序,您可以显示类似的体验.
现在,进入网格.
这里的关键是你从一个Grid实际上是3列,一个是1列.因此,您需要修改ColumnSpan单元格的属性.
什么到目前为止,你画有3个Columns,每一个Width的GridLength *.从那里开始.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
Run Code Online (Sandbox Code Playgroud)
接下来,我们要设置Rows.最好将行数设置为您需要的最大数量,这是我的计数6.如果将它们全部设置为Auto,则空Rows(在横向方向)将消失.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
Run Code Online (Sandbox Code Playgroud)
现在,创建一些基本内容.我只是要创建一堆不同的StackPanels并将它们命名为它们.
我将默认Grid/Row值设置为Landscape.我也在'Second Row'使用两行(包含StackPanels 1和2).两个StackPanels都有RowSpan2个补偿.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Name="HeaderRow" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"/>
<StackPanel Name="StackPanel1" Grid.Row="1" Grid.Column="0" Grid.RowSpan="2"/>
<StackPanel Name="Content" Grid.Row="1" Grid.Column="1"/>
<StackPanel Name="BlueSection" Grid.Row="2" Grid.Column="1"/>
<StackPanel Name="StackPanel2" Grid.Row="1" Grid.Column="2" Grid.RowSpan="2"/>
<StackPanel Name="FooterRow" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)
现在我们为您的Landscape定位提供了一个很好的定义.它会根据其中的内容自动垂直调整大小,但您可以自由地执行任何您想要的最小尺寸.
现在我们已经完成了这个,我们只需要VisualStates为不同的尺寸创建一些.在一个方面,VisualState我们将准确定义我们已经完成的工作.另一方面,我们将创建一个新的.我暂时将它们命名为"Landscape"和"Portrait",但我建议做"Mid"和"Wide"之类的操作,然后根据Bounds给定的内容定义哪些内容.为了空间,我省略了以前的定义.
从技术上讲,我们不需要包含Landscape定义,但我将其作为附加示例包含在内.
注意:在第二张图片中,您有StackPanel2 以下内容 Footer.我在下面反映了这一点.如果需要更改,只需更改StackPanel2to 4和of 的行定义Footer即可5.
<Grid>
...
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="OrientationStates">
<!-- What we've already defined -->
<VisualState x:Name="Landscape">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<!-- Stack Panel 2 -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<!-- Content -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<! -- Blue Section -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<!-- Footer -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Footer">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
</VisualState>
<!-- The New Section -->
<VisualState x:Name="Portrait">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<!-- Stack Panel 2 -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="5"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<!-- Content -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<! -- Blue Section -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<!-- Footer -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Footer">
<DiscreteObjectKeyFrame KeyTime="0" Value="4"/>
</ObjectAnimationUsingKeyFrames>
</VisualState>
</VisualStateGroup>
<VisualStateManager.VisualStateGroups>
</Grid>
Run Code Online (Sandbox Code Playgroud)
你几乎完成.你需要的只是让你Page倾听WindowSizeChanged并回应它!它需要得到你的参考Grid.因此,我建议添加x:Name="ContentGrid"或类似于基本Grid定义.如:
<Grid x:Name="ContentGrid">
Run Code Online (Sandbox Code Playgroud)
我的例子WindowSizeChanged将假设你已经这样做了.
private void WindowSizeChanged(object sender, WindowSizeChangedEventArgs windowSizeChangedEventArgs)
{
if (windowSizeChangedEventArgs.Size.Width < 800)
{
VisualStateManager.GoToState(ContentGrid, "Portrait", true);
}
else
{
VisualStateManager.GoToState(ContentGrid, "Landscape", true);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,在你Page的OnNavigatedTo和OnNavigatedFrom...
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Window.Current.SizeChanged += WindowSizeChanged;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
Window.Current.SizeChanged -= WindowSizeChanged;
}
Run Code Online (Sandbox Code Playgroud)
确保SizeChanged event在从页面导航时删除处理程序,否则您的应用程序将无限期地保留页面在内存中的副本.这是如何创建一个有趣的内存泄漏.
就是这样!在更改大小时,您的主页将通知您的网格它需要重新配置自己,它将以所述方式执行此操作.显然你不能直接粘贴它,但你应该能够使用它.确保将更TargetNames改为命名控件.
希望这有助于编码!