当ScrollBar变为可见时,WPF Scrollviewer DesiredSize不会增加 [英] WPF Scrollviewer DesiredSize does not increase when ScrollBar gets Visible
问题描述
我有一个WPF UserControl
(在ElementHost
内部),其中的ScrollViewer
包含ItemsControl
. HorizontalScrollbarVisibility
设置为Auto
,因此如果不需要滚动,则ScrollBar
会被隐藏.
I have a WPF UserControl
(inside an ElementHost
) with a ScrollViewer
that contains an ItemsControl
. The HorizontalScrollbarVisibility
is set to Auto
, so if no scrolling is necessary, the ScrollBar
gets hidden.
我的要求是,如果ScrollBar
被显示/隐藏,ElementHost
会相应地调整其高度.为此,我正在监听SizeChanged
事件,在EventHandler
中获得ScrollViewer
的DesiredSize
,然后将DesiredSize.Height
传递给ElementHost
.
My requirement is, that if the ScrollBar
gets shown/hidden, the ElementHost
does adjust it's height accordingly. To achieve that, I'm listening to the SizeChanged
event, I get the DesiredSize
of the ScrollViewer
in the EventHandler
, then I pass DesiredSize.Height
to the ElementHost
.
- 2. 3.
一种方法,它起作用:在ScrollBar
可见的情况下(情况1),我扩大窗口,直到ItemsControl
的所有项目都可见,ScrollBar
消失,ElementHost
调整为减小的高度(情况) 2). ScrollBar
隐藏后,DesiredSize
实际上变小了.
One way, this works: With ScrollBar
visible (situation 1), I enlarge my window until all items of the ItemsControl
are visible, the ScrollBar
disappears, the ElementHost
adjusts to reduced height (situation 2). DesiredSize
actually got smaller the moment the ScrollBar
is hidden.
但是,另一种方法却行不通:在ScrollBar
不可见的情况下(情况2),我减小了窗口的大小,直到需要ScrollBar
并出现为止. DesiredSize
保持不变,并且ElementHost
不会调整(情况3).
The other way, though, it doesn't work: With ScrollBar
not visible (situation 2), I reduce my window size until a ScrollBar
is necessary and appears. DesiredSize
stays the same, and the ElementHost
does not adjust (situation 3).
有什么想法吗?
这是Scrollviewer
的xaml,其中包含一些MVVM内容,但是请不要挂在嘴上,实际上是,为什么当ScrollBar
出现时,为什么DesiredSize
没有增加?为什么只收缩?
This is the xaml of the Scrollviewer
, with some MVVM stuff, but don't get hung up on this, the point really is, why does the DesiredSize
not increase when the ScrollBar
appears? Why is it shrink only?
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden" >
<i:Interaction.Behaviors>
<beh:HeightChangedBehavior HeightChangedCommand="{Binding HeightChangedCommand}" />
</i:Interaction.Behaviors>
<ItemsControl ItemsSource="{Binding TabHeaders}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="models:TabHeaderButtonModel">
<RadioButton Content="{Binding Caption}" IsChecked="{Binding IsChecked, Mode=TwoWay}" GroupName="Tabs"
Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding}"
Style="{StaticResource TabHeaderToggleButtonStyle}">
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
ScrollViewer样式(基本上是默认的WPF):
ScrollViewer style (basically default WPF):
<Style x:Key="ScrollViewerStyle1" TargetType="{x:Type ScrollViewer}">
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid x:Name="Grid" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle x:Name="Corner" Grid.Column="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Grid.Row="1"/>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
<ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
<ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}" Style="{DynamicResource ScrollBarStyle1}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
推荐答案
我必须通过获取ScrollViewer的内容所需的高度并添加ScrollBar高度(如果可见)来计算所需的高度.
I had to calculate the desired height by getting the ScrollViewer's content desired height and adding the ScrollBar height if visible.
这对我来说仍然有点尴尬,因此,如果您有更好的解决方案,我会很乐意更改接受的答案.
This still feels slightly awkward to me, so if you have a better solution, I'll gladly change the accepted answer.
public class HeightChangedBehavior : Behavior<ScrollViewer>
{
public ICommand HeightChangedCommand { get { return (ICommand)GetValue(HeightChangedCommandProperty); } set { SetValue(HeightChangedCommandProperty, value); } }
public static readonly DependencyProperty HeightChangedCommandProperty = DependencyProperty.Register("HeightChangedCommand", typeof(ICommand), typeof(HeightChangedBehavior), new PropertyMetadata(null));
protected override void OnAttached()
{
this.AssociatedObject.ScrollChanged += AssociatedObject_ScrollChanged;
base.OnAttached();
}
/// <summary>
/// Calculates the desired height for the scrollviewer, as the sum of its content
/// desired height and, if visible, the horizontal scrollbar height.
/// </summary>
void AssociatedObject_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer sv = (ScrollViewer)sender;
// get content height
double height = ((FrameworkElement)sv.Content).DesiredSize.Height;
if (sv.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
{
// add scrollbar height
height += (double)sv.FindResource(SystemParameters.HorizontalScrollBarHeightKey); // template of scrollbar should use this key
}
int intHeight = (int)Math.Ceiling(height); // whole pixels
// execute the command
ICommand cmd = this.HeightChangedCommand;
if (cmd != null && intHeight != sv.ActualHeight)
cmd.Execute(intHeight);
}
}
这篇关于当ScrollBar变为可见时,WPF Scrollviewer DesiredSize不会增加的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!