アプリケーション
範囲セレクターを含むアプリケーションを構築しています。これは、1つのSlider
派生クラス内に含まれる2つのカスタム描画UserControl
コントロールで構成されます。範囲セレクターコントロールは、ほとんどの場合HorizonalScrollBarが表示されるScrollViewer
内に含まれます。
サンプルアプリケーションコード:(テキストの壁の謝罪)
Window.xaml(ウィンドウファイル):
<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>
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>
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
}
問題提供されているサンプルコードのほとんどは退屈であり、その仕組みはかなりうまく機能しています。私が抱えている問題は、特にメインウィンドウにあるScrollViewer
コントロールの視覚的な問題です。 ScrollViewer
のいずれかがフォーカスを獲得すると(たとえば、マウスクリックから)、ScrollViewer
はSlider
の水平オフセットを自動的に調整しているようです。
行動を再現する
Slider
をクリックすると、ScrollViewerが自動的に調整され、水平オフセットが認識された「コンテンツ」の開始位置にシフトすることがわかります。これらの症状は、スクロールペインの両端で発生します。
実行時のアプリケーションのスクリーンショット(詳細を明確にするために、アプリケーションは200%拡大されています):
左のスライダーがクリックされたときの動作のスクリーンショット:
私がしたいこと:
スライダーがスライダーの端を超えているように見えるときに(両端の)いずれかのスライダー項目をクリックすると(スライダーの範囲は上部の黒いバーで示されます)Ido n'tScrollViewerが水平オフセットを自動的に調整するようにします。
疑わしい問題:
問題は、ScrollViewerが、実際に描画されたコンテンツが開始する場所から15ピクセル(両方のスライダーの描画幅)で始まる子の実際の「コンテンツ」を認識することだと思います。メインウィンドウのSliderTest
コントロール内に15ピクセルのパディングを含めたため、Canvasは描画するだけです。このパディングを削除すると、ScrollViewerにはスライダーのCanvasが表示されません。
[〜#〜] edit [〜#〜]:パディングは問題ではないようです。理由については、コメントをお読みください。
私が試したこと
メインウィンドウのOnPreviewMouseDownイベントをオーバーライドすることを検討しました。ここでの問題は、両方のスライダーを正常に動作させたいということです。イベントを「処理済み」に設定すると、スライダーが完全に機能しなくなります。
注:
範囲セレクターコントロール内のスライダー(この例ではSliderTestと呼ばれます)は、両方とも1ピクセルの幅である必要があります。スライダーは、時間選択範囲の終わりを超えて15ピクセル拡張できる必要があります(参照については、上部の黒いバーを参照してください)。
この小説の長さの問題を読んでいただきありがとうございます。
デフォルトでは、コントロールが論理フォーカスを受け取ると、FrameworkElementは独自の BringIntoView メソッドを呼び出します(キーボードフォーカスがある場合は、OnGotFocusメソッド内から)。その結果、 RequestBringIntoView イベントが生成され、要素ツリーがバブルアップして、祖先要素が要素のその部分を表示できるようになります。 ScrollViewerはこのイベントをリッスンし、最終的には関連するIScrollInfo/ScrollContentPresenterでMakeVisibleを呼び出します。これにより、その部分が表示されます(パネルは子の配置方法を認識しているため)。次に、返されたrectを受け取り、それ自体のその部分を表示するように要求します(元の要素が表示されるようにするために何らかのアクションが必要なネストされた要素がある場合)。したがって、この動作を抑制する1つの方法は、スライダーでRequestBringIntoViewイベントを処理し、処理されたイベントをマークすることです。