use*_*056 32 wpf scrollviewer wpf-controls
应用程序
我正在构建一个包含范围选择器的应用程序.这包含Slider一个UserControl派生类中包含的两个自定义绘制控件.然后,范围选择器控件包含在ScrollViewer大多数时间都可见的HorizonalScrollBar中.
示例应用程序代码:(文本墙的应用)
Window.xaml(Window文件):
<Grid>
<ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled">
<local:SliderTest x:Name="slider"
LowerValue="0"
UpperValue="10"
Minimum="0"
Maximum="100" Width="900" Height="165" Padding="15,0,15,0" HorizontalAlignment="Left">
</local:SliderTest>
</ScrollViewer>
</Grid>
Run Code Online (Sandbox Code Playgroud)
SliderTest.xaml:
<UserControl x:Class="scrollviewerDemoProblem.SliderTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Name="root"
xmlns:local="clr-namespace:scrollviewerDemoProblem"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ControlTemplate x:Key="simpleSlider" TargetType="{x:Type Slider}">
<Border SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.Thumb>
<Thumb x:Name="Thumb" FlowDirection="LeftToRight" Width="15">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Canvas>
<Path x:Name="test1" StrokeThickness="0" Fill="DarkGreen">
<Path.Data>
<GeometryGroup FillRule="NonZero">
<PathGeometry>
<PathGeometry.Figures>
<PathFigure IsClosed="True" StartPoint="0,150" IsFilled="True">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="-15,150" />
<LineSegment Point="-15,0" />
<LineSegment Point="0,0" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
</Canvas>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track.Thumb>
</Track>
</Grid>
</Border>
</ControlTemplate>
<ControlTemplate x:Key="simpleSliderRight" TargetType="{x:Type Slider}">
<Border SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.Thumb>
<Thumb x:Name="Thumb" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Width="15">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Canvas>
<Path Stroke="Black" StrokeThickness="0" Fill="DarkCyan">
<Path.Data>
<GeometryGroup FillRule="NonZero">
<PathGeometry>
<PathGeometry.Figures>
<PathFigure IsClosed="True" StartPoint="0,150">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="15,150" />
<LineSegment Point="15,0" />
<LineSegment Point="0,0" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
</Canvas>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track.Thumb>
</Track>
</Grid>
</Border>
</ControlTemplate>
</UserControl.Resources>
<Grid x:Name="Gridd" VerticalAlignment="Top" Height="165" >
<Border x:Name="timeScaleBorder" Width="auto" Height="15" VerticalAlignment="Top" Background="Black">
<Canvas x:Name="timeCanvas" Width="auto" Height="15">
</Canvas>
</Border>
<Border x:Name="background" BorderThickness="1,1,1,1" BorderBrush="Black" VerticalAlignment="Center" Height="150"
Margin="0,15,0,0" Background="White" />
<Slider x:Name="LowerSlider"
Minimum="{Binding ElementName=root, Path=Minimum}"
Maximum="{Binding ElementName=root, Path=Maximum}"
Value="{Binding ElementName=root, Path=LowerValue, Mode=TwoWay}"
Template="{StaticResource simpleSlider}"
Margin="0,15,0,0" />
<Slider x:Name="UpperSlider"
Minimum="{Binding ElementName=root, Path=Minimum}"
Maximum="{Binding ElementName=root, Path=Maximum}"
Value="{Binding ElementName=root, Path=UpperValue, Mode=TwoWay}"
Template="{StaticResource simpleSliderRight}"
Margin="0,15,0,0" />
</Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
SliderText.xaml.cs:
public partial class SliderTest : UserControl
{
public SliderTest()
{
InitializeComponent();
}
#region Dependency properties, values etc.
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register("Minimum", typeof(double), typeof(SliderTest), new UIPropertyMetadata(0d));
public double LowerValue
{
get { return (double)GetValue(LowerValueProperty); }
set { SetValue(LowerValueProperty, value); }
}
public static readonly DependencyProperty LowerValueProperty =
DependencyProperty.Register("LowerValue", typeof(double), typeof(SliderTest), new UIPropertyMetadata(0d));
public double UpperValue
{
get { return (double)GetValue(UpperValueProperty); }
set { SetValue(UpperValueProperty, value); }
}
public static readonly DependencyProperty UpperValueProperty =
DependencyProperty.Register("UpperValue", typeof(double), typeof(SliderTest), new UIPropertyMetadata(0d));
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register("Maximum", typeof(double), typeof(SliderTest), new UIPropertyMetadata(1d));
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
问题提供的
大多数示例代码都很无聊,并且它的机制非常好.我遇到的问题是一个视觉问题,特别ScrollViewer是我在主窗口中的控件.的ScrollViewer似乎是自动调整水平的偏移ScrollViewer时任一的Slider的获得焦点(从鼠标单击例如).
再现行为
Slider,您会注意到ScrollViewer会自动调整以将水平偏移移动到感知"内容"开始的位置.这些症状出现在滚动窗格的任一端.
应用程序运行时的屏幕截图(为了细节清晰,应用程序以200%放大):

单击左滑块时的行为的屏幕截图:

我想要发生什么:
当滑块看起来超出滑块的末端(滑块范围由顶部的黑条表示)时,当我点击任一滑块项目(在任一端)时,我不希望ScrollViewer自动调整它的水平偏移.
疑似问题:
我怀疑问题是ScrollViewer感知到它的孩子的实际"内容"从实际绘制的内容开始的15个像素(两个滑块的绘制宽度)开始.Canvas只绘制,因为我SliderTest在主窗口的控件内部包含了15个像素的填充,如果删除此填充,则ScrollViewer不会显示任何Slider的Canvas.
编辑:看起来填充不是问题,阅读评论为什么.
我尝试过的事情
我试图调查覆盖主窗口的OnPreviewMouseDown事件.这里的问题是我仍然希望两个Slider都能正常运行,将事件设置为Handled会导致Slider完全停止工作.
笔记:
范围选择器控件(本例中称为SliderTest)中的Slider必须都具有1像素的宽度.滑块必须能够在时间选择范围的末尾延伸15个像素(请参阅顶部的黑色条以供参考).
感谢您阅读这个新颖的问题.
小智 43
默认情况下,当控件接收到逻辑焦点时,FrameworkElement会调用自己的BringIntoView方法(如果它具有键盘焦点,则从其OnGotFocus方法中调用).这导致生成RequestBringIntoView事件,该事件冒泡元素树以允许祖先元素将元素的该部分带入视图.ScrollViewer侦听此事件,最终将在关联的IScrollInfo/ScrollContentPresenter上调用MakeVisible,然后将其留给面板以使该部分进入视图(因为面板将知道它如何安排其子项).然后它接收返回的矩形它接收回来并要求将其自身的那部分带入视图(如果你有嵌套元素需要一些动作以确保原始元素被带入视图).因此,抑制此行为的一种方法是处理滑块上的RequestBringIntoView事件并标记处理的事件.