ScrollViewer
が存在するグリッド行の高さがAuto
に設定されている場合、ScrollViewer
は、見えている高さよりも大きくすることができます。スクロールバーを機能させるには、高さを固定数または星の高さに設定する必要があります
ただし、この要件があります。2つのグリッド行に2つの異なるビューがあり、これらの2つのビューを切り替えるトグルボタンがあります。1つのビューが表示されると、もう1つのビューは非表示/非表示になります。したがって、2つの行を定義しました。どちらの高さもAuto
として設定されています。そして、各行のビューの可視性をViewModelのブールプロパティにバインドします(1つはTrue
からVisible
に、もう1つはTrue
からCollapsed
。アイデアは、1つのビューの可視性がCollapsed
の場合、グリッドの行/ビューの高さが自動的に0に変更されることです。
表示/非表示のビューは正常に機能しています。ただし、1つのビューにはScrollViewer
があり、前述のとおり、行の高さがAuto
に設定されている場合は機能しません。 ScrollViewer
を自動的に機能させながら、このような要件を満たす方法を誰かに教えてもらえますか?高さを分離コードで設定できると思います。しかし、MVVMを使用しているため、追加の通信/通知が必要になります。それを行う簡単な方法はありますか?
可能であれば、高さをAuto
から*
に変更します。
例:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="525">
<StackPanel Orientation="Horizontal" Background="LightGray">
<Grid Width="100">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="_scroll1">
<Border Height="300" Background="Red" />
</ScrollViewer>
<TextBlock Text="{Binding ElementName=_scroll1, Path=ActualHeight}" Grid.Row="1"/>
</Grid>
<Grid Width="100">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="_scroll2">
<Border Height="300" Background="Green" />
</ScrollViewer>
<TextBlock Text="{Binding ElementName=_scroll2, Path=ActualHeight}" Grid.Row="1"/>
</Grid>
</StackPanel>
</Window>
MVVMでは、ScrollViewer
の高さを親コントロール(常にActualHeight
型)のUIElement
にバインドするのがうまくいきました。
ActualHeight
は、コントロールが画面に描画された後にのみ設定される読み取り専用のプロパティです。ウィンドウのサイズが変更されると、変更される場合があります。
<StackPanel>
<ScrollViewer Height="{Binding Path=ActualHeight,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UIElement}}">
<TextBlock Text=Hello"/>
</ScrollViewer>
</StackPanel>
親コントロールの高さが無限である場合、より大きな問題が発生します。高さが無限でないコントロールにぶつかるまで、すべての親の高さを設定し続ける必要があります。
スヌープはこれのために絶対に貴重です:
XAML要素の「高さ」が0
またはNaN
の場合は、次のいずれかを使用して値を設定できます。
Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UIElement}}"
VerticalAlignment="Stretch"
Height="Auto"
ヒント:VerticalAlignment="Stretch"
を使用してGrid
の子である場合は<RowDefinition Height="*">
を使用し、それが機能しない場合はBinding RelativeSource...
を使用します。
興味がある場合は、この問題を修正するための以前のすべての試みを以下に示します。
これも使用できます:
Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}"
役立つ情報: WPF-MaxHeightと組み合わせたAuto Height を参照してください。
何も動作しないように見える場合は、親のActualHeight
が0(何も表示されていない)または巨大(スクロールビューアが表示される必要がない)のいずれかが原因であると考えられます。グリッドのネストが深く、スクロールビューアが右下にある場合、これはさらに問題になります。
ActualHeight
のStackPanel
を見つけます。プロパティで、ActualHeight
とActualWidth
を戻すWord "Actual"
でフィルタリングします。ActualHeight
がゼロの場合は、MinHeight
を使用して最小の高さを与え、少なくとも何かが見えるようにします。ActualHeight
が大きすぎて画面の端からはみ出る場合(つまり16,000)、MaxHeight
を使用して適切な最大の高さを指定すると、スクロールバーが表示されます。スクロールバーが表示されたら、さらにクリーンアップできます。
Height
またはStackPanel
のGrid
を親のActualHeight
にバインドします。最後に、ScrollViewer
をこのStackPanel
の中に入れます。
これは時々失敗する可能性があることがわかります:
Height="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}"
理由?バインドが失敗すると、高さがゼロになり、何も表示されなくなります。アクセスできない要素にバインドしている場合、バインドは失敗する可能性があります。ビジュアルツリーをup
に移動し、次にリーフノードにdown
した場合(たとえば、親グリッドまで、行のActualHeight
までをバインドすると、バインドは失敗します。そのグリッドに接続されています)。これが、ActualWidth
のRowDefinition
へのバインドが機能しない理由です。
私は、UserControlの最初のHeight=Auto
要素までのすべての親要素の<Grid>
を確認することで、これを機能させることになりました。
ScrollViewerに固定の高さを設定できますが、行の最初の子がScrollViewerになり、行の高さが自動になるため、グリッドの2番目の行にもその高さがあることを考慮する必要があります。または、ScrollViewerの高さをレイアウト内の別のコントロール。あなたのレイアウトがどのように見えるかわかりません。
最後に、どちらも好きではない場合は、swiszczが提案するように行の高さを*に設定するか、wpfをハックして、すべてのパラレルユニバースなどで可能なすべてをレイアウトできる独自のカスタムパネルを作成します。 :)
私が発見したのは、ScrollViewer
をHeight=Auto
またはあなたは彼の親を得るHeigh Actual Size
をそのコンテナに適用します。
私の場合、UserControl
のような
<Grid Margin="0,0,0,0" Padding="0,2,0,0">
<ScrollViewer Height="Auto" ZoomMode="Disabled" IsVerticalScrollChainingEnabled="True" VerticalAlignment="Top"
HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Disabled"
VerticalScrollMode="Enabled" VerticalScrollBarVisibility="Visible">
<ListView ItemsSource="{x:Bind PersonalDB.View, Mode=OneWay}" x:Name="DeviceList"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ItemTemplate="{StaticResource ContactListViewTemplate}"
SelectionMode="Single"
ShowsScrollingPlaceholders="False"
Grid.Row="1"
Grid.ColumnSpan="2"
VerticalAlignment="Stretch"
BorderThickness="0,0,0,0"
BorderBrush="DimGray">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel AreStickyGroupHeadersEnabled="False" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="local1:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
Style="{ThemeResource TitleTextBlockStyle}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</ScrollViewer>
</Grid>
そして、ContentControl
内にあるPage
に動的に追加します。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="0,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="70" />
<RowDefinition Height="*" MinHeight="200" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<ContentControl x:Name="UIControlContainer" />
</Grid>
</Grid>
Heigh
のRow
は*
ContentControl
に入力するとき、このコードをLoaded
イベントで使用します
UIControlContainer.Content = new UIDeviceSelection() {
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
Height = UIControlContainer.ActualHeight,
Width = UIControlContainer.ActualWidth
};
また、ContentControl
のサイズが変更された場合は、UserControl
のサイズを更新する必要があります。
UIControlContainer.SizeChanged += UIControlContainer_SizeChanged;
private void UIControlContainer_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (UIControlContainer.Content != null)
{
if (UIControlContainer.Content is UserControl)
{
(UIControlContainer.Content as UserControl).Height = UIControlContainer.ActualHeight;
(UIControlContainer.Content as UserControl).Width = UIControlContainer.ActualWidth;
}
}
}
楽しい!
追伸実際、私はUWPのためにそれをしました。