2017-09-15 79 views
4

我已經爲我的應用程序創建了自定義滑塊和縮略圖模板。除了PART_SelectionRange Rectangle之外,它的工作方式與預期相同,稍微在拇指後面開始,到達最大值時明顯遠遠落後於它。WPF自定義滑塊PART_SelectionRange滯後於拇指

我不知道如何解決這個問題,因爲看起來問題出在控制PART_SelectionRange Rectangle大小的任何類的行爲上。 (對不起,我不知道如何內聯)。

<ControlTemplate x:Key="SliderThumbHorizontalDefault" TargetType="{x:Type Thumb}"> 
    <Grid> 
     <!-- SliderThumb --> 
     <Path x:Name="grip" Data="M-0.4,6.4 C1.2,1 9,1 10.5,6.5 12,11.787571 5.0267407,18.175417 5.0267407,18.175417 5.0267407,18.175417 -2,11.8 -0.4,6.4 z" 
      Fill="White" Stretch="Fill" SnapsToDevicePixels="True" 
      Stroke="Black" StrokeThickness="1" UseLayoutRounding="True" /> 
     <ContentPresenter Margin="0 4 0 0" Content="{Binding Value, RelativeSource={RelativeSource AncestorType={x:Type Slider}}}" TextBlock.Foreground="Black" TextBlock.FontSize="20" TextBlock.TextAlignment="Center" /> 
    </Grid> 
</ControlTemplate> 

<ControlTemplate x:Key="SliderHorizontal" TargetType="{x:Type Slider}"> 
    <ControlTemplate.Resources> 
     <vc:TickConverter x:Key="TickConverter" /> 
    </ControlTemplate.Resources> 
    <Grid Height="{StaticResource SliderHeight}"> 
     <Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="0" 
       Background="White" 
       CornerRadius="{Binding ActualHeight, Converter={StaticResource HalvingConverter}, ElementName=TrackBackground}"> 
      <!-- This rectangle is what lags behind! --> 
      <Rectangle x:Name="PART_SelectionRange" Fill="SlateBlue" 
         HorizontalAlignment="Left" RadiusY="3" RadiusX="3" /> 
     </Border> 
     <Track x:Name="PART_Track" > 
      <Track.Thumb> 
       <Thumb x:Name="Thumb" Focusable="False" Width="35" Height="47" OverridesDefaultStyle="True" 
          Template="{StaticResource SliderThumbHorizontalDefault}" Margin="-14.65,-55,-16,12"/> 
      </Track.Thumb> 
     </Track> 
    </Grid> 
    <ControlTemplate.Triggers> 
     <Trigger Property="IsSelectionRangeEnabled" Value="true"> 
      <Setter Property="Visibility" TargetName="PART_SelectionRange" Value="Visible" /> 
     </Trigger> 
     <Trigger Property="IsKeyboardFocused" Value="true"> 
      <Setter Property="Foreground" TargetName="Thumb" Value="Blue" /> 
     </Trigger> 
    </ControlTemplate.Triggers> 
</ControlTemplate> 

<Style TargetType="{x:Type Slider}"> 
    <Setter Property="MinHeight" Value="{StaticResource SliderHeight}" /> 
    <Setter Property="MaxHeight" Value="{StaticResource SliderHeight}" /> 
    <Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" /> 
    <Setter Property="IsSelectionRangeEnabled" Value="True" /> 
    <Setter Property="Background" Value="Transparent" /> 
    <Setter Property="BorderBrush" Value="Transparent" /> 
    <Setter Property="Foreground" Value="{StaticResource SliderThumb.Static.Foreground}" /> 
    <Setter Property="SelectionStart" Value="{Binding Minimum, RelativeSource={RelativeSource Self}}" /> 
    <Setter Property="SelectionEnd" Value="{Binding Value, RelativeSource={RelativeSource Self}}" /> 
    <Setter Property="Template" Value="{StaticResource SliderHorizontal}" /> 
</Style> 

在這一點上,我不知道我應該試圖修改。我相信我已經嘗試過改變xaml中所有有意義的屬性,所以我認爲問題出現在Slider類中,但無法理解它在哪裏。

回答

1

不幸的是,您只能使用自定義Style s和ControlTemplate s來更改Slider的此行爲。

原因是Slider控件根據Thumb的寬度調整選擇範圍的寬度。這會導致選擇範圍欄「回退」,同時將滑塊位置移向其值Maximum。如果您希望選擇範圍完全遵循Value,則需要將Thumb寬度設置爲0.但是,顯然,您將無法移動拇指,因爲不會再有命中測試。

這是對應的選擇範圍的大小和位置的調整current implementation

if (DoubleUtil.AreClose(range, 0d) || (DoubleUtil.AreClose(trackSize.Width, thumbSize.Width))) 
{ 
    valueToSize = 0d; 
} 
else 
{ 
    valueToSize = Math.Max(0.0, (trackSize.Width - thumbSize.Width)/range); 
} 

rangeElement.Width = ((SelectionEnd - SelectionStart) * valueToSize); 
if (IsDirectionReversed) 
{ 
    Canvas.SetLeft(rangeElement, (thumbSize.Width * 0.5) + Math.Max(Maximum - SelectionEnd, 0) * valueToSize); 
} 
else 
{ 
    Canvas.SetLeft(rangeElement, (thumbSize.Width * 0.5) + Math.Max(SelectionStart - Minimum, 0) * valueToSize); 
} 

你現在有兩個選擇:

  • 實現自己的滑塊控件不調整其選擇範圍根據Thumb寬度
  • 或從您的ControlTemplate中的選擇矩形中刪除"PART_SelectionRange"名稱並使用Binding個s的IValueConverter S(或Behavior S,或附加屬性)來控制的外觀手動
0

繼@dymanoid的回答,我手動執行的行爲(無法創建一個新的滑塊後)。

我刪除了PART_SelectionRange控件(必須使它透明或不能編譯),用這個矩形替換它。

<Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="0" 
     Background="{StaticResource SliderThumb.Track.Background}" 
     CornerRadius="{Binding ActualHeight, Converter={StaticResource HalvingConverter}, ElementName=TrackBackground}"> 
    <Rectangle x:Name="SelectionRange" Fill="{StaticResource SliderThumb.Track.BackgroundSelected}" 
       HorizontalAlignment="Left" RadiusY="3" RadiusX="3"> 
     <Rectangle.Width> 
      <MultiBinding Converter="{StaticResource SliderToSelectionWidthConverter}"> 
       <Binding Path="Value" RelativeSource="{RelativeSource TemplatedParent}"/> 
       <Binding Path="Maximum" RelativeSource="{RelativeSource TemplatedParent}"/> 
       <Binding Path="Minimum" RelativeSource="{RelativeSource TemplatedParent}"/> 
       <Binding Path="ActualWidth" RelativeSource="{RelativeSource TemplatedParent}"/> 
      </MultiBinding> 
     </Rectangle.Width> 
    </Rectangle> 
</Border> 

相關的是它的寬度綁定到Slider的Value,Minimum,Maximum和ActualWidth屬性。使用此轉換器:

class SliderToSelectionWidthConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     var Value = (double) values[0]; 
     var Minimum = (double) values[1]; 
     var Maximum = (double) values[2]; 
     var ActualWidth = (double) values[3]; 
     return (1 - (Value - Minimum)/(Maximum - Minimum)) * ActualWidth; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

這些值可用於計算SelectionRange矩形的實際寬度。爲什麼這不是在默認的Slider中完成的,這超出了我的想象。