2011-10-19 114 views
5

我似乎已經在這裏達到了某種MVVM的突破點。使用MVVM從事件觸發動畫

當底層視圖模型對象的「狀態」屬性發生更改時,我想讓控件的不透明度動畫半秒(DoubleAnimation從0.5到1.0)。我首先使用DataTrigger實現了這一點,但由於我沒有找到一種方法來對任何更改做出反應,只是給定的值,我必須在設置它之前始終將VM對象「Status」屬性翻轉爲特殊的「pending」值達到預期的價值。 (?有沒有辦法BTW應對任何變化)

這是哈克,所以我開始EventTriggers而不是擺弄......

這是我到目前爲止已經試過:

  1. 使用正常的EventTrigger

這似乎需要一個RoutedEvent,但這反過來要求我的基礎視圖模型對象從DependencyObject繼承。

  1. 使用i:Interaction.Triggers

這樣我可以聽和作出反應的正常.NET事件,但我還沒有找到一種方法,使用這種方法來啓動一個StoryBoard

  1. 使用i:Interaction.Triggers續寫Behavior

這個實驗不及上,我發現沒有辦法我的自定義行爲附加到其相關的控制的事實。

這就是XAML看起來像:

<cc:MyControl> 
     <i:Interaction.Triggers> 
      <i:EventTrigger EventName="Updated"> 
       <i:Interaction.Behaviors> 
        <cv:OpacityBehavior Duration="0:0:0:5" /> 
       </i:Interaction.Behaviors> 
      </i:EventTrigger> 
     </i:Interaction.Triggers> 

而這裏的自定義行爲:

class OpacityBehavior : Behavior<MyControl> 
{ 
    public Duration Duration { get; set; } 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     var animation = new DoubleAnimation(0.5, 1, Duration, FillBehavior.HoldEnd); 
     var associatedObject = lookupVisualParent(this); 
     associatedObject.BeginAnimation(UIElement.OpacityProperty, animation); 
    } 
} 

因爲XAML解析器需要它那沒有工作直接連接到顯示「myControl 「但我需要將其附加到事件觸發器。然後,我嘗試這個辦法:

class OpacityBehavior : Behavior<DependencyObject> 
{ 
    public Duration Duration { get; set; } 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     var animation = new DoubleAnimation(0.5, 1, Duration, FillBehavior.HoldEnd); 
     var associatedObject = lookupVisualParent(this); 
     associatedObject.BeginAnimation(UIElement.OpacityProperty, animation); 
    } 

    private UIElement lookupVisualParent(DependencyObject dObj) 
    { 
     if (dObj is UIElement) 
      return (UIElement) dObj; 

     if (dObj == null) 
      return null; 

     return lookupVisualParent(LogicalTreeHelper.GetParent(dObj)); 
    } 
} 

這個失敗的事實,lookupVisualParent不起作用。該行爲的邏輯父項始終爲null

這讓我覺得這應該是一個相當普遍的任務?有沒有解決這個問題的好方法?我發現奇怪的是,我將編寫我的視圖模型類,以便它們從DependencyObject派生,以便在事件觸發時啓動動畫。

乾杯

回答

4

你可以簡單地用一個標誌:設置一個標誌,在VM上稱爲「RecentlyChangedFlag」。每當適當的值改變時,將其脈衝到true,然後false。你可以這樣做:

private bool _changedFlag; 
public bool ChangedFlag 
{ 
    get 
    { 
     if (_changedFlag) 
     { 
      _changedFlag = false; 
      OnPropertyChanged("ChangedFlag"); 
      return true; 
     } 
     // (else...) 
     return false; 
    } 
    protected set 
    { 
     _changedFlag = value; 
     OnPropertyChanged("ChangedFlag"); 
    } 
} 

I.e.,當您想要啓動動畫時,使用上述代碼設置ChangedFlag = true。在WPF查詢真值後,它將被重置爲false。

然後,當RecentlyChangedFlag的值是true時發生動畫,例如EnterAction

希望有所幫助。

+0

謝謝,但這就是我最初「解決」它(使用DataTrigger),但正如我在OP中指出的那樣,這很不好。我對WPF相當陌生,所以它可能是觸發虛擬機的行爲/動畫的正常方式,但對我來說,這似乎正在解決一個不應該存在的限制。難道你不能在虛擬機中觸發事件的動畫? –

+0

ViewModel存在將模型轉換爲視圖可以使用的內容。因此,它是完成這種事情的最佳地點。這不是那種駭人的海事組織和一個標誌,表明重要的變化應該存在於虛擬機中。只要ViewModel獨立存在,這不是問題。一個ViewModel有一個標誌來表示你所說的任何'事件' - 如果你把它稱爲正確的東西,它看起來不太合適? –

+1

我對此不會很虔誠,但看起來很奇怪,它不可能從事件中觸發動畫。畢竟,事件在那裏表示狀態的變化。不得不添加第二個屬性來向第一個狀態發送狀態更改是一種解決方法。我很驚訝地發現WPF提供的工具缺乏。在這種特殊情況下,我當然可以與「國有資產解決方案」一起生活,但我預計未來我的虛擬機課程將充滿此類特性。必須有更好的方法,對吧? –