2008-09-17 6 views
15

ViewModel/Presentation Model이 사용 중일 때 진행 애니메이션을 트리거하려고합니다. IsBusy 속성이 있고 ViewModel UserControl DataContext로 설정됩니다. IsBusy 속성이 true 일 때 "progressAnimation"스토리 보드를 트리거하는 가장 좋은 방법은 무엇입니까? UserControl 수준에서 Event-Triggers를 추가 만하면 혼합 할 수 있으며 데이터 템플릿에서 속성 트리거 만 만들 수 있습니다.WPF 데이터 트리거 및 스토리 보드

"progressAnimation"은 사용자 정의 컨트롤의 리소스로 정의됩니다.

내가 UserControl을의 스타일로 DataTriggers를 추가했지만, 나는 다음과 같은 오류가 스토리 보드를 시작하려고하면

'System.Windows.Style' value cannot be assigned to property 'Style' 
of object'Colorful.Control.SearchPanel'. A Storyboard tree in a Style 
cannot specify a TargetName. Remove TargetName 'progressWheel'. 

ProgressWheel 내가 애니메이션을하기 위해 노력하고있어 개체의 이름입니다 그래서 대상 이름을 제거하는 것은 obvisouly 내가 원하는 것입니다.

데이터 바인딩 기술을 사용하여 XAML에서이 문제를 해결하고 이벤트를 노출시키지 않고 코드를 통해 애니메이션을 시작/중지해야합니다.

답변

29

당신이 원하는 것은 progressWheel 자체에 애니메이션을 선언 할 수있다 : XAML : 뒤에

<UserControl x:Class="TriggerSpike.UserControl1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Height="300" Width="300"> 
<UserControl.Resources> 
    <DoubleAnimation x:Key="SearchAnimation" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:4"/> 
    <DoubleAnimation x:Key="StopSearchAnimation" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:4"/> 
</UserControl.Resources> 
<StackPanel> 
    <TextBlock Name="progressWheel" TextAlignment="Center" Opacity="0"> 
     <TextBlock.Style> 
      <Style> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding IsBusy}" Value="True"> 
         <DataTrigger.EnterActions> 
          <BeginStoryboard> 
           <Storyboard> 
            <StaticResource ResourceKey="SearchAnimation"/> 
           </Storyboard> 
          </BeginStoryboard> 
         </DataTrigger.EnterActions> 
         <DataTrigger.ExitActions> 
          <BeginStoryboard> 
           <Storyboard> 
            <StaticResource ResourceKey="StopSearchAnimation"/> 
           </Storyboard> 
          </BeginStoryboard> 
         </DataTrigger.ExitActions> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </TextBlock.Style> 
     Searching 
    </TextBlock> 
    <Label Content="Here your search query"/> 
    <TextBox Text="{Binding SearchClause}"/> 
    <Button Click="Button_Click">Search!</Button> 
    <TextBlock Text="{Binding Result}"/> 
</StackPanel> 

코드 :

using System.Windows; 
using System.Windows.Controls; 

namespace TriggerSpike 
{ 
    public partial class UserControl1 : UserControl 
    { 
     private MyViewModel myModel; 

     public UserControl1() 
     { 
      myModel=new MyViewModel(); 
      DataContext = myModel; 
      InitializeComponent(); 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      myModel.Search(myModel.SearchClause); 
     } 
    } 
} 

뷰 모델 :

using System.ComponentModel; 
using System.Threading; 
using System.Windows; 

namespace TriggerSpike 
{ 
    class MyViewModel:DependencyObject 
    { 

     public string SearchClause{ get;set;} 

     public bool IsBusy 
     { 
      get { return (bool)GetValue(IsBusyProperty); } 
      set { SetValue(IsBusyProperty, value); } 
     } 

     public static readonly DependencyProperty IsBusyProperty = 
      DependencyProperty.Register("IsBusy", typeof(bool), typeof(MyViewModel), new UIPropertyMetadata(false)); 



     public string Result 
     { 
      get { return (string)GetValue(ResultProperty); } 
      set { SetValue(ResultProperty, value); } 
     } 

     public static readonly DependencyProperty ResultProperty = 
      DependencyProperty.Register("Result", typeof(string), typeof(MyViewModel), new UIPropertyMetadata(string.Empty)); 

     public void Search(string search_clause) 
     { 
      Result = string.Empty; 
      SearchClause = search_clause; 
      var worker = new BackgroundWorker(); 
      worker.DoWork += worker_DoWork; 
      worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
      IsBusy = true; 
      worker.RunWorkerAsync(); 
     } 

     void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      IsBusy=false; 
      Result = "Sorry, no results found for: " + SearchClause; 
     } 

     void worker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      Thread.Sleep(5000); 
     } 
    } 
} 

희망이 있습니다.

1

IsBusy 속성 대신 RoutedEvent를 사용하는 것이 좋습니다. OnBusyStarted 및 OnBusyStopped 이벤트를 발생시키고 적절한 요소에서 이벤트 트리거를 사용하십시오.

+1

글쎄, 그게 내가 원하는 것입니다. avoid ...하지만, 그렇게하겠습니다 : UIElement에서 파생되지 않은 클래스에서 RoutedEvent를 구현하는 방법에 대한 예는 무엇입니까? –

1

DataObject 클래스의 PropertyChanged 이벤트에 가입하고 Usercontrol 수준에서 RoutedEvent를 발생시킬 수 있습니다. RoutedEvent를 들어

우리가 DependancyObject

+0

당신이 옳다고 생각합니다. 가장 명백한 솔루션처럼 UserControl 솔기에서 RoutedEvent를 노출합니다 ... 그러나 아직 데이터를 기반으로 임의의 스토리 보드를 실행하는 것을 포기하지 않았습니다. 그러나 입력에 감사드립니다! –

0

당신은 속성이 변경 될 때 애니메이션을 시작 Trigger.EnterAction을 사용할 수 있습니다에서 파생 된 클래스가해야 할 일입니다.

<Trigger Property="IsBusy" Value="true"> 
    <Trigger.EnterActions> 
     <BeginStoryboard x:Name="BeginBusy" Storyboard="{StaticResource MyStoryboard}" /> 
    </Trigger.EnterActions> 
    <Trigger.ExitActions> 
     <StopStoryboard BeginStoryboardName="BeginBusy" /> 
    </Trigger.ExitActions> 
</Trigger> 
+0

내가 말했듯이 이것은 사용자 컨트롤 레벨에 있으며 PropertyTriggers (Property- 또는 DataTriggers가 아닌) 만 허용합니다. 또한 IsBusy는 UserControl의 속성이 아니라 DataContext (ViewModel)로 설정된 개체에서 –

4

애니메이션을 적용 할 요소에 애니메이션을 직접 연결한다는 대답은 단순한 경우에이 문제를 해결하지만 여러 요소를 대상으로해야하는 복잡한 애니메이션이있는 경우에는 실제로 작동하지 않습니다. (물론 각 요소에 애니메이션을 첨부 할 수는 있지만 관리가 매우 끔찍해집니다.) DataTrigger을 사용하여 명명 된 요소를 대상으로하는 애니메이션을 실행할 수있게하는 다른 방법이 있습니다.

WPF에서 트리거를 연결할 수있는 곳은 요소, 스타일 및 템플릿입니다. 그러나 처음 두 옵션은 여기서 작동하지 않습니다. 첫 번째 요소는 WPF가 요소에 직접 DataTrigger을 사용할 수 없으므로 배제됩니다. (필자가 아는 한 이것에 대한 특별한 이유가 없다. 내가 기억하는 한, WPF 팀에 수년 전에 사람들에게 물었을 때, 그들은 그것을지지하고 싶었지만 그렇게하지 않았다고했다. 그것을 작동하게하는 시간을 가져라.) 그리고보고 된 오류 메시지에서 말하듯이 스타일과 연관된 애니메이션에서 명명 된 요소를 대상으로 지정할 수 없기 때문에 스타일이 부족합니다.

이렇게하면 템플릿이 남습니다. 그리고 이것을 위해 컨트롤이나 데이터 템플릿을 사용할 수 있습니다.

이 구성을 사용하면 WPF는 템플릿 내부의 명명 된 요소를 애니메이션으로 참조하게되어 기쁘게 생각합니다. (애니메이션과 템플릿 내용을 여기에 비워 두었습니다. 실제 애니메이션 내용으로 내용을 채우는 것이 분명합니다.)

템플릿에서는 작동하지만 스타일에서는 작동하지 않는 이유는 템플릿에서 정의한 명명 된 요소는 항상 존재하므로 해당 템플릿의 범위 내에서 정의 된 애니메이션이 해당 요소를 참조하는 것이 안전합니다. 스타일은 일반적으로 서로 다른 시각적 트리가있는 여러 요소에 적용될 수 있기 때문에 일반적으로 스타일과 관련이 없습니다. (약간의 좌절감으로 인해 필요한 요소가있을 수 있다는 것을 확신 할 수있는 상황에서도이 작업을 수행 할 수 없지만, 오른쪽의 명명 된 요소에 애니메이션을 바인딩하는 것이 매우 어려워지는 무언가가있을 수 있습니다 WPF에는 스타일 요소를 효율적으로 재사용 할 수있는 최적화 기능이 많이 포함되어 있으므로이 중 하나가이 기능을 지원하기가 어렵다는 점입니다.

관련 문제