2014-10-28 4 views
3

MVVM 응용 프로그램에서 작업 중이며 ProgressBar에 속성이 변경 될 때 새 값으로 부드럽게 움직 이도록하고 싶습니다. C#을 사용하여이 질문에 대한 몇 가지 답변을 보았습니다. 그러나 템플릿 내부에서이 작업을 수행하는 것을 선호합니다. 내가 가지고있는 문제는 이벤트와 스토리 보드를 올바르게 설정하고 타겟팅하는 것입니다. 여기에 내가 현재 가지고있는 것입니다 :WPF 템플릿에서 부드럽게 애니메이션 된 ProgressBar

진행은

여기에서 트리거 코드를 갔던 스타일 - (바로 트리거)

    <ControlTemplate.Triggers> 
        <EventTrigger RoutedEvent="RangeBase.ValueChanged"> 
         <BeginStoryboard> 
          <Storyboard> 
           <DoubleAnimation 
            Storyboard.TargetName="???????" 
            Storyboard.TargetProperty="Value" 
            To="???????" Duration="0:0:5" /> 
          </Storyboard> 
         </BeginStoryboard> 
        </EventTrigger> 

을 바 - : http://msdn.microsoft.com/en-us/library/system.windows.controls.progressbar(v=vs.110).aspx.

어떻게이 템플릿을 사용하는 모든 컨트롤에 적용되도록 TargetName을 템플릿 자체로 설정합니까? 수신 가치에 "받는 사람"을 어떻게 설정합니까? "Binding"값을 가져 오는 방법이있는 것처럼 보이지만 Valuebar 및 Max 모두 progressbar 요소에 바인딩되어 있습니다. 무엇을 사용해야할지 어떻게 알 수 있습니까?

여기 참조를 위해 전체 템플릿입니다 :

<Style x:Key="ProgressStyle" TargetType="{x:Type ProgressBar}"> 
    <Setter Property="OverridesDefaultStyle" Value="True" /> 
    <Setter Property="SnapsToDevicePixels" Value="True" /> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type ProgressBar}"> 
       <Grid MinHeight="14" MinWidth="20"> 
        <Border x:Name="BaseRectangle" Background="{StaticResource BaseColor}" CornerRadius="10,0,10,0"></Border> 
        <Border x:Name="GlassRectangle" CornerRadius="10,0,10,0" Background="{StaticResource GlassFX}" Panel.ZIndex="10"></Border> 
        <Border x:Name="animation" CornerRadius="10,0,10,0" Opacity=".7" Background="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left"></Border> 
        <Border x:Name="PART_Indicator" CornerRadius="10,0,10,0" Background="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left"></Border> 
        <Border x:Name="PART_Track" BorderThickness="1" CornerRadius="10,0,10,0" BorderBrush="Black"></Border> 
        <Border x:Name="BordeCabeceraSombra" BorderThickness="2" CornerRadius="10,0,10,0" BorderBrush="DarkGray" Opacity=".2" Margin="1,1,1,0"></Border> 
        <Label x:Name="Progress" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontWeight="Bold" Foreground="White" Opacity=".7" Content="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}}"></Label> 
       </Grid> 
       <ControlTemplate.Triggers> 
        <EventTrigger RoutedEvent="RangeBase.ValueChanged"> 
         <BeginStoryboard> 
          <Storyboard> 
           <DoubleAnimation 
            Storyboard.TargetName="???????" 
            Storyboard.TargetProperty="Value" 
            From="???????" To="???????" Duration="0:0:5" /> 
          </Storyboard> 
         </BeginStoryboard> 
        </EventTrigger> 
        <Trigger Property="IsIndeterminate" Value="True"> 
         <Setter Property="Visibility" TargetName="Progress" Value="Hidden"></Setter> 
         <Setter Property="Background" TargetName="PART_Indicator"> 
          <Setter.Value> 
           <MultiBinding> 
            <MultiBinding.Converter> 
             <wintheme:ProgressBarHighlightConverter/> 
            </MultiBinding.Converter> 
            <Binding Source="{StaticResource GlowFXProgressAnimated}"/> 
            <Binding Path="ActualWidth" ElementName="BaseRectangle"/> 
            <Binding Path="ActualHeight" ElementName="BaseRectangle"/> 
           </MultiBinding> 
          </Setter.Value> 
         </Setter> 
        </Trigger> 
        <Trigger Property="IsEnabled" Value="False"> 
         <Setter Property="Opacity" Value=".5"></Setter> 
        </Trigger> 
       </ControlTemplate.Triggers> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

어떤 도움을 주시면 감사하겠습니다!

+0

난 당신이 XAML에서 스토리 보드를 사용하여이 작업을 수행 할 수 있습니다 생각하지 않습니다,하지만 당신은 롤 수 붙은 행동으로 행동. 애니메이션은 C# 코드에서 계속 적용되지만 코드는 재사용 가능한 동작으로 캡슐화되며 사용자의 스타일에 따라 동작을 활성화 할 수 있습니다. –

답변

2

는 사실이에 대한 해결책을 찾을 수 없습니다. 나는 결국 내 자신의 통제를 작성했다. 이것은 기술적으로 질문에 대한 답변이 아니지만 게시 할 수도 있습니다. 누군가 MVVM의 애니메이션 진행 제어를 찾고 있다면 도움이 될 수 있습니다. 여기

namespace Card_System.Controls 
{ 
    /// <summary> 
    /// Interaction logic for StatProgressBar.xaml 
    /// </summary> 
    public partial class StatProgressBar : UserControl 
    { 
     private double _trackWidth; 
     private bool _isAnimate; 
     private bool _isRefresh; 

     public StatProgressBar() 
     { 
      InitializeComponent(); 

      var descriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(Border)); 
      if (descriptor != null) 
      { 
       descriptor.AddValueChanged(TrackBorder, ActualWidth_ValueChanged); 
      } 
     } 



     public event PropertyChangedEventHandler PropertyChanged; 

     private double _barValueSet; 
     public double BarValueSet 
     { 
      get { return _barValueSet; } 
      set 
      { 
       _barValueSet = value; 
       OnPropertyChanged("BarValueSet"); 
       _isAnimate = true; 
       AnimateWidth(); 
      } 
     } 

     public double BarValueDesired 
     { 
      get { return (double)GetValue(BarValueProperty); } 
      set { SetValue(BarValueProperty, value); } 
     } 

     public static readonly DependencyProperty BarValueProperty = 
      DependencyProperty.Register("BarValueDesired", typeof(double), typeof(StatProgressBar), new UIPropertyMetadata(0.0d, new PropertyChangedCallback(BarValueDesired_PropertyChanged))); 

     public double BarMaximum 
     { 
      get { return (double)GetValue(BarMaximumProperty); } 
      set { SetValue(BarMaximumProperty, value); } 
     } 

     public static readonly DependencyProperty BarMaximumProperty = 
      DependencyProperty.Register("BarMaximum", typeof(double), typeof(StatProgressBar), new UIPropertyMetadata(0.0d)); 


     public static void BarValueDesired_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      //Set BarValue to the value of BarValueDesired BEFORE it was just changed. 
      ((StatProgressBar)d).BarValueSet = (double)e.OldValue; 
     } 

     public Brush BarColor 
     { 
      get { return (Brush)GetValue(BarColorProperty); } 
      set { SetValue(BarColorProperty, value); } 
     } 

     public static readonly DependencyProperty BarColorProperty = 
      DependencyProperty.Register("BarColor", typeof(Brush), typeof(StatProgressBar), new UIPropertyMetadata(Brushes.White, new PropertyChangedCallback(BarColor_PropertyChanged))); 

     public static void BarColor_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      ((StatProgressBar)d).BarFill.Background = (Brush)e.NewValue; 

     } 

     private void ActualWidth_ValueChanged(object a_sender, EventArgs a_e) 
     { 
      _trackWidth = TrackBorder.ActualWidth; 
      _isRefresh = true; 
      AnimateWidth(); 
     } 

     public void AnimateWidth() 
     { 
      if (_isAnimate && _isRefresh) 
      { 
       double StartPoint = new double(); 
       double EndPoint = new double(); 
       double PercentEnd = new double(); 
       double PercentStart = new double(); 

       PercentStart = BarValueSet/BarMaximum; 
       StartPoint = _trackWidth * PercentStart; 
       PercentEnd = BarValueDesired/BarMaximum; 
       EndPoint = _trackWidth * PercentEnd; 

       DoubleAnimation animation = new DoubleAnimation(StartPoint, EndPoint, TimeSpan.FromSeconds(3)); 
       this.BarFill.BeginAnimation(Border.WidthProperty, animation); 
      } 
      else return; 
     } 

     protected void OnPropertyChanged(string name) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(name)); 
      } 
     } 
    } 
} 

그리고

은 XAML입니다 :

<Grid> 
<Grid MinHeight="14" MinWidth="20"> 
    <Border x:Name="BaseRectangle" Background="{StaticResource BaseColor}" CornerRadius="0,0,0,0"/> 
    <Border x:Name="TrackBorder" BorderThickness="1" CornerRadius="0,0,0,0" BorderBrush="Black" Panel.ZIndex="20"/> 
    <Border x:Name="BarFill" HorizontalAlignment="Left" Opacity=".7" Background="White"/> 
    <Border x:Name="GlassOverlay" CornerRadius="0,0,0,0" Background="{StaticResource GlassFX}" Panel.ZIndex="10"/> 
    <Border x:Name="GlassOverlayBorder" BorderThickness="4" CornerRadius="0,0,0,0" BorderBrush="DarkGray" Opacity=".2" Panel.ZIndex="12"/> 
</Grid> 

0

비슷한 개념을 다른 포럼에 게시했으며 링크는 아래에 언급되어 있습니다. 이게 당신을 도울 수 있기를 바랍니다.

http://www.codeproject.com/Tips/837994/WPF-Preloader-Control

건배

+0

여기에 설명 된 것이 더 도움이된다. –

+0

대답에 감사드립니다. 나는 결국 내 자신의 사용자 정의 컨트롤을 만드는 것을 끝내었다. – Terrordoll

0

나는이 문제가 해결 알고,하지만 난 UserControl을을 만들 필요가없는 정말 좋은 구현을 발견했다. "이발 극 효과"를 모방하여 즉시 사용할 수 있습니다.

<SolidColorBrush x:Key="ProgressBarBorderBrush" Color="Transparent" /> 
<SolidColorBrush x:Key="ProgressBarBackgroundBrush" Color="White" /> 
<SolidColorBrush x:Key="ProgressBarTrackBackgroundBrush" Color="#63D055" /> 

<Style x:Key="{x:Type ProgressBar}" TargetType="{x:Type ProgressBar}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type ProgressBar}"> 
       <local:ClippingBorder x:Name="BorderBackground" CornerRadius="3" BorderThickness="0" 
         BorderBrush="{StaticResource ProgressBarBorderBrush}" 
         Background="{StaticResource ProgressBarBackgroundBrush}"> 
        <Grid> 
         <VisualStateManager.VisualStateGroups> 
          <VisualStateGroup x:Name="CommonStates"> 
           <VisualState x:Name="Determinate" /> 
           <VisualState x:Name="Indeterminate" /> 
          </VisualStateGroup> 
         </VisualStateManager.VisualStateGroups> 
         <Border x:Name="PART_Track" Margin="0" BorderThickness="0" CornerRadius="3" /> 
         <Border x:Name="PART_Indicator" Margin="0" BorderThickness="0" CornerRadius="3" HorizontalAlignment="Left" 
           Background="{StaticResource ProgressBarTrackBackgroundBrush}" ClipToBounds="True"> 
          <Border x:Name="DiagonalDecorator" Width="5000"> 
           <Border.Background> 
            <DrawingBrush TileMode="Tile" Stretch="None" Viewbox="0,0,1,1" Viewport="0,0,36,34" ViewportUnits="Absolute"> 
             <DrawingBrush.RelativeTransform> 
              <TranslateTransform X="0" Y="0" /> 
             </DrawingBrush.RelativeTransform> 
             <DrawingBrush.Drawing> 
              <GeometryDrawing Brush="#48C739" Geometry="M0,0 18,0 36,34 18,34 Z" /> 
             </DrawingBrush.Drawing> 
            </DrawingBrush> 
           </Border.Background> 
           <Border.Triggers> 
            <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 
             <BeginStoryboard> 
              <Storyboard> 
               <DoubleAnimation 
                Storyboard.TargetProperty="(Border.Background).(DrawingBrush.RelativeTransform).(TranslateTransform.X)" 
                From="0" To=".36" RepeatBehavior="Forever" Duration="0:0:18" /> 
              </Storyboard> 
             </BeginStoryboard> 
            </EventTrigger> 
           </Border.Triggers> 
          </Border> 
         </Border> 
        </Grid> 
       </local:ClippingBorder> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

원하는대로 속도와 색상을 편집하면됩니다.

+0

내가 틀렸다면 나에게 맞춰라. 그러나 이것은 살아 움직이는 배경을 가진 진행 바를위한 틀 (template)이다. 내가 찾고 있던 것은 현재 값에서 새로운 값으로 움직이는 진행 막대였습니다. 즉, 점프 대신 채우거나 배수하는 진행 막대가있었습니다. 나는이 템플릿을 유지할 것이다, 고마워. 다음과 같은 것이 필요할 때를 절대 알지 못할 것입니다. – Terrordoll

+0

StoryBoard 트리거를 다음 새 값으로 이동하는 것처럼 보이게하려면 StoryBoard 트리거를 ValueChanged 이벤트에 추가 할 수 있습니다. 나는이 테스트를 직접 해보지는 않았지만 아마 시작하기에 좋은 곳 일 것이다. 행운을 빕니다! –

1

나는 더 좋은 방법이라고 생각합니다.

이렇게하려면 동작을 만들 수 있습니다. (MVVM WPF)

만들기 클래스 :

class ProgresBarAnimateBehavior : Behavior<ProgressBar> 
{ 
    bool _IsAnimating = false; 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     ProgressBar progressBar = this.AssociatedObject; 
     progressBar.ValueChanged += ProgressBar_ValueChanged; 
    } 

    private void ProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) 
    { 
     if (_IsAnimating) 
      return; 

     _IsAnimating = true; 

     DoubleAnimation doubleAnimation = new DoubleAnimation 
      (e.OldValue, e.NewValue, new Duration(TimeSpan.FromSeconds(0.3)), FillBehavior.Stop); 
     doubleAnimation.Completed += Db_Completed; 

     ((ProgressBar)sender).BeginAnimation(ProgressBar.ValueProperty, doubleAnimation); 

     e.Handled = true; 
    } 

    private void Db_Completed(object sender, EventArgs e) 
    { 
     _IsAnimating = false; 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
     ProgressBar progressBar = this.AssociatedObject; 
     progressBar.ValueChanged -= ProgressBar_ValueChanged; 
    } 
} 

그리고 단순히 사용 :

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
xmlns:b="clr-namespace:YOURNAMESPACE.Behaviors" 

<ProgressBar Height="7" 
      Value="{Binding LoadingValue}"> 

    <i:Interaction.Behaviors> 
     <b:ProgresBarAnimateBehavior /> 
    </i:Interaction.Behaviors> 
</ProgressBar> 
+0

행동 방식은 분명 더 좋은 방법입니다. 고마워. – johnDisplayClass

관련 문제