2017-01-22 6 views
0

Ich versuche, einen schwebenden Schieberegler zu erstellen. Da Animationen sind Freezable, außerdem, sobald Sie den Schieberegler ziehen, ändert sich der Wert und der Daumen springt auf die Position, wäre es schwierig, den tatsächlichen Daumen zu animieren.Wie macht man einen schwebenden Slider?

Also was ich tat war, einen gefälschten Daumen stattdessen zu animieren (ich nenne es süchtig Daumen) und mache den tatsächlichen Daumen transparent. das ging ziemlich cool, aber es gibt einige Probleme.

, wie Sie in der folgenden gif zu sehen, die Margin von Haken Daumen ist auf die Breite der Spur nicht ansprechbar: (. Linker Rand von Code-Behind animiert)

enter image description here

Wie kann ich der Spielraum reagiert? (Ich möchte dieses Problem nicht von Code hinten beheben)

Dieser Teil ist die Vorlage für den Stil des Schiebers.

<Grid Width="{TemplateBinding Width}" 
     Height="{TemplateBinding Height}"> 

    <Track x:Name="PART_Track"> 
     <Track.DecreaseRepeatButton> 
      <RepeatButton x:Name="PART_SelectionRange" 
       BorderBrush="{TemplateBinding BorderBrush}" 
       Background="{TemplateBinding Background}" 
       Style="{StaticResource PlaybackScrollRepeatButtonStyle}" 
       Command="{x:Static Slider.DecreaseLarge}"/> 
     </Track.DecreaseRepeatButton> 
     <Track.IncreaseRepeatButton> 
      <RepeatButton 
       BorderBrush="{TemplateBinding BorderBrush}" 
       Background="{TemplateBinding Background}" 
       Style="{StaticResource PlaybackScrollRepeatButtonStyle}" 
       Command="{x:Static Slider.IncreaseLarge}"/> 
     </Track.IncreaseRepeatButton> 
     <!-- Transparent thumb with width of 1px and auto height. --> 
     <Track.Thumb> 
      <Thumb x:Name="Thumb" 
       Style="{StaticResource PlaybackSliderHiddenThumbStyle}"/> 
     </Track.Thumb> 
    </Track> 

    <!-- This is the fake thumb. its margin is animated in codebehind. --> 
    <ContentControl x:Name="HookedThumb" HorizontalAlignment="Left" 
     Style="{StaticResource PlaybackSliderHookedThumbStyle}" 
     Background="{StaticResource Playback.Slider.Thumb.Brush}" 
     BorderBrush="{StaticResource Playback.Slider.Thumb.Border}"/> 
</Grid> 

Ich kenne den Grund, warum dies nicht reagiert, weil ich HorizontalAlignment="Left" für die Haken Daumen bin. Wenn ich HorizontalAlignment="Stretch" verwende, reagiert es immer noch nicht. das ist, was Sie sehen:

enter image description here

(Code-Behind geändert, weil Marge auf unterschiedliche Weise berechnet wird)

Nun ist dies näher am Daumen, aber immer noch nicht ansprechbar.

Ich bin offen mit jeder Lösung. Mach dir keine Sorgen über die Animation. Ich werde damit umgehen. Was ich will, ist, dass der süchtig machende Daumen so reagiert wie der Hauptdaumen.

Die andere Idee, die ich hatte, war es, Grenze mit Daumen daran befestigt zu machen, und nur die Breite der Grenze zu animieren, aber ich kann nicht den richtigen Stil bekommen. jede Hilfe wird geschätzt.


Hier ist der Code hinter falls Sie wissen wollen (wenn HorizontalAlignment="Stretch")

// following will animate margin of hooked thumb to the location of thumb. 

var cc = (ContentControl)PlaybackSlider.Template.FindName("HookedThumb", PlaybackSlider); 
var track = (Track)PlaybackSlider.Template.FindName("PART_Track", PlaybackSlider); 
var selection = (RepeatButton)PlaybackSlider.Template.FindName("PART_SelectionRange", PlaybackSlider); 
var thumb = track.Thumb; 

cc.Margin = new Thickness(-track.ActualWidth + cc.Width, 0, 0, 0); // starting margin 

var keyframe = new SplineThicknessKeyFrame(); // holds the target keyframe. 

var animator = new ThicknessAnimationUsingKeyFrames // this will animate margin 
{ 
    KeyFrames = new ThicknessKeyFrameCollection { keyframe }, 
    BeginTime = TimeSpan.Zero, 
    Duration = TimeSpan.FromMilliseconds(200), 
    DecelerationRatio = 1 
}; 

var storyboard = new Storyboard // we use storyboard so we can stop and begin animation at any time. 
{ 
    Children = new TimelineCollection { animator } 
}; 

// setup storyboard with target property and dependency object. 
Storyboard.SetTarget(animator, cc); 
Storyboard.SetTargetProperty(animator, new PropertyPath(MarginProperty)); 

Action beginAnimation =() => 
{ 
    storyboard.Stop(); // stop animation. change target, begin animation again. 

    var left = -track.ActualWidth + selection.Width*2; // calculate left margin 

    var correction = left; // set correction to the left margin 

    // prevent moving thumb out of range 
    if (correction < -track.ActualWidth + cc.Width) correction = -track.ActualWidth + cc.Width; 
    if (left + cc.Width > track.ActualWidth) 
     correction = track.ActualWidth - cc.Width; 

    // set new target frame 
    keyframe.Value = new Thickness(correction, 0, 0, 0); 

    storyboard.Begin(); 
}; 

// following are the handlers that begins the animation. 

PlaybackSlider.ValueChanged += (o, e) => 
{ 
    if(thumb.IsDragging) return; 
    beginAnimation(); 
}; 
thumb.DragStarted += (o, e) => beginAnimation(); 
thumb.DragDelta += (o, e) => beginAnimation(); 
thumb.DragCompleted += (o, e) => beginAnimation(); 

Hier werden die Stile sind: ausgeschlossen Trigger.

<!-- playback repeat button style --> 
<Style x:Key="PlaybackScrollRepeatButtonStyle" TargetType="{x:Type RepeatButton}" BasedOn="{StaticResource {x:Type RepeatButton}}"> 
    <Setter Property="IsTabStop" Value="False"/> 
    <Setter Property="Focusable" Value="False"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type RepeatButton}"> 
       <Border Background="Transparent"> 
        <Rectangle Fill="{TemplateBinding Background}" 
           Stroke="{TemplateBinding BorderBrush}" 
           VerticalAlignment="Center" 
           StrokeThickness="0.5" 
           Height="3"/> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

<!-- playback slider thumb--> 
<Style x:Key="PlaybackSliderHiddenThumbStyle" TargetType="{x:Type Thumb}" BasedOn="{StaticResource {x:Type Thumb}}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Thumb}"> 
       <Canvas Background="Transparent" Width="1px"/> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

<!-- playback slider thumb decoy--> 
<Style x:Key="PlaybackSliderHookedThumbStyle" TargetType="{x:Type ContentControl}" BasedOn="{StaticResource {x:Type ContentControl}}"> 
    <Setter Property="IsEnabled" Value="False"/> 
    <Setter Property="IsHitTestVisible" Value="False"/> 
    <Setter Property="Focusable" Value="False"/> 
    <Setter Property="IsTabStop" Value="False"/> 
    <Setter Property="Width" Value="17"/> 
    <Setter Property="Height" Value="17"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type ContentControl}"> 
       <Border Background="Transparent"> 
        <Ellipse x:Name="Ellipse" 
         Fill="{TemplateBinding Background}" 
         Stroke="{TemplateBinding BorderBrush}" 
         StrokeThickness="1.5"/> 
       </Border> 

      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

<!-- playback slider style --> 
<Style x:Key="PlaybackSliderStyle" TargetType="{x:Type Slider}" BasedOn="{StaticResource {x:Type Slider}}"> 
    <Setter Property="Background" Value="{StaticResource Playback.Slider.Brush}"/> 
    <Setter Property="BorderBrush" Value="{StaticResource Playback.Slider.Border}"/> 
    <Setter Property="Foreground" Value="{StaticResource Playback.Slider.SelectionRange}"/> 
    <Setter Property="SelectionStart" Value="{Binding Minimum, RelativeSource={RelativeSource Self}}"/> 
    <Setter Property="SelectionEnd" Value="{Binding Value, RelativeSource={RelativeSource Self}}"/> 
    <Setter Property="IsSelectionRangeEnabled" Value="True"/> 
    <Setter Property="IsMoveToPointEnabled" Value="True"/> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Slider}"> 

       <Grid Width="{TemplateBinding Width}" 
         Height="{TemplateBinding Height}"> 

        <Track x:Name="PART_Track"> 
         <Track.DecreaseRepeatButton> 
          <RepeatButton x:Name="PART_SelectionRange" 
           BorderBrush="{TemplateBinding BorderBrush}" 
           Background="{TemplateBinding Background}" 
           Style="{StaticResource PlaybackScrollRepeatButtonStyle}" 
           Command="{x:Static Slider.DecreaseLarge}"/> 
         </Track.DecreaseRepeatButton> 
         <Track.IncreaseRepeatButton> 
          <RepeatButton 
           BorderBrush="{TemplateBinding BorderBrush}" 
           Background="{TemplateBinding Background}" 
           Style="{StaticResource PlaybackScrollRepeatButtonStyle}" 
           Command="{x:Static Slider.IncreaseLarge}"/> 
         </Track.IncreaseRepeatButton> 
         <Track.Thumb> 
          <Thumb x:Name="Thumb" 
           Style="{StaticResource PlaybackSliderHiddenThumbStyle}"/> 
         </Track.Thumb> 
        </Track> 

        <ContentControl x:Name="HookedThumb" HorizontalAlignment="Stretch" 
         Style="{StaticResource PlaybackSliderHookedThumbStyle}" 
         Background="{StaticResource Playback.Slider.Thumb.Brush}" 
         BorderBrush="{StaticResource Playback.Slider.Thumb.Border}"/> 
       </Grid> 

      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Antwort

0

konnte ich dieses Problem beheben, nachdem this answer sehen,

I Tag-Eigenschaft verwendet, und Multi-Bindung mit Hilfe von mehrfach-Wandler, um dieses Problem zu beheben.

enter image description here

Das ist der neue Stil für Schieber.

<Grid Width="{TemplateBinding Width}" 
     Height="{TemplateBinding Height}"> 

    <Track x:Name="PART_Track"> 
     <Track.DecreaseRepeatButton> 
      <RepeatButton x:Name="PART_SelectionRange" 
       BorderBrush="{TemplateBinding BorderBrush}" 
       Background="{TemplateBinding Background}" 
       Style="{StaticResource PlaybackScrollRepeatButtonStyle}" 
       Command="{x:Static Slider.DecreaseLarge}"/> 
     </Track.DecreaseRepeatButton> 
     <Track.IncreaseRepeatButton> 
      <RepeatButton 
       BorderBrush="{TemplateBinding BorderBrush}" 
       Background="{TemplateBinding Background}" 
       Style="{StaticResource PlaybackScrollRepeatButtonStyle}" 
       Command="{x:Static Slider.IncreaseLarge}"/> 
     </Track.IncreaseRepeatButton> 
     <Track.Thumb> 
      <Thumb x:Name="Thumb" 
       Style="{StaticResource PlaybackSliderThumbStyle}"/> 
     </Track.Thumb> 
    </Track> 

    <WrapPanel VerticalAlignment="Center"> 
     <Border x:Name="Border" Margin="0,0,-8.5,0"> 
      <!-- Tag is used for animating width --> 
      <Border.Tag> 
       <system:Double>0.0</system:Double> 
      </Border.Tag> 
      <Border.Width> 
       <MultiBinding Converter="{StaticResource MultiplyConverter}"> 
        <Binding Path="ActualWidth" ElementName="PART_Track"/> 
        <Binding Path="Tag" RelativeSource="{RelativeSource Self}" /> 
       </MultiBinding> 
      </Border.Width> 
     </Border> 
     <ContentControl x:Name="ThumbShadow" 
      Style="{StaticResource PlaybackSliderThumbStyleShadow}" 
      Background="{StaticResource Playback.Slider.Thumb.Brush}" 
      BorderBrush="{StaticResource Playback.Slider.Thumb.Border}"/> 
    </WrapPanel> 
</Grid> 

Hier ist Code-Behind für Animieren Tag-Eigenschaft innerhalb des Bereichs von 0 bis 1

private void AttachAnimation(Slider slider) 
{ 
    var track = (Track)slider.Template.FindName("PART_Track", slider); 
    var thumb = (Thumb)slider.Template.FindName("Thumb", slider); 
    var shadow = (ContentControl)slider.Template.FindName("ThumbShadow", slider); 
    var selection = (RepeatButton)slider.Template.FindName("PART_SelectionRange", slider); 
    var border = (Border)slider.Template.FindName("Border", slider); 
    var center = shadow.Width/2; 

    DoubleAnimation animation = new DoubleAnimation 
    { 
     DecelerationRatio = 1, 
     Duration = TimeSpan.FromMilliseconds(200) 
    }; 

    Storyboard storyboard = new Storyboard 
    { 
     Children = new TimelineCollection { animation } 
    }; 

    Storyboard.SetTarget(animation, border); 
    Storyboard.SetTargetProperty(animation, new PropertyPath("Tag")); 

    Action beginAnimation =() => 
    { 
     var correction = selection.ActualWidth; 
     if (selection.ActualWidth + center > track.ActualWidth) 
      correction = track.ActualWidth - center; // prevent going outside of bounds. 

     var ratio = correction/track.ActualWidth; 

     if (animation.To == ratio) 
      return; // to prevent animation freeze when there is no need for animation change. 

     animation.To = ratio; 

     storyboard.Stop(border); 
     storyboard.Begin(border, true); 
    }; 

    slider.ValueChanged += async (o, args) => 
    { 
     if(thumb.IsDragging) return; // drag delta will handle animation. 
     await Task.Delay(10); // wait for value changes 
     beginAnimation(); 
    }; 
    thumb.DragStarted += (o, args) => beginAnimation(); 
    thumb.DragDelta += (o, args) => beginAnimation(); 
    thumb.DragCompleted += async (o, args) => 
    { 
     if (args.Canceled) await Task.Delay(10); // wait for value changes 
     beginAnimation(); 
    }; 

    // at startup initialize values. 
    var init = selection.ActualWidth; 
    if (selection.ActualWidth + center > track.ActualWidth) init -= center; 
    border.Tag = init/track.ActualWidth; 

    storyboard.Begin(); // this will warm up animation to be ready for first time. 
} 
Verwandte Themen