2011-10-19 38 views
5

Tôi dường như đã đạt đến một số điểm phá vỡ MVVM tại đây.Kích hoạt hoạt ảnh từ một sự kiện bằng MVVM

Tôi muốn kiểm soát độ mờ của nó được hoạt ảnh trong nửa giây (DoubleAnimation từ 0.5 đến 1.0) khi đối tượng mô hình xem bên dưới có thuộc tính "Trạng thái" của nó đã thay đổi. Tôi đã đạt được điều này lúc đầu bằng cách sử dụng DataTrigger nhưng vì tôi chưa tìm thấy cách phản ứng với bất kỳ thay đổi nào, chỉ là một giá trị nhất định, tôi phải luôn lật thuộc tính "Trạng thái" của đối tượng VM thành giá trị "đang chờ xử lý" đặc biệt trước khi đặt với giá trị dự định của nó. (? Có cách nào để phản ứng với bất kỳ sự thay đổi btw)

Đây là hacky vì vậy tôi bắt đầu loay hoay với EventTriggers thay vì ...

Đây là những gì tôi đã cố gắng cho đến nay:

  1. Sử dụng thông thường EventTrigger

Điều này dường như yêu cầu RoutedEvent nhưng yêu cầu đối tượng mô hình xem cơ bản của tôi kế thừa từ DependencyObject.

  1. Sử dụng i:Interaction.Triggers

Bằng cách đó tôi có thể nghe và phản ứng với các sự kiện bình thường NET nhưng tôi đã không tìm thấy một cách để bắt đầu một StoryBoard sử dụng cách tiếp cận đó.

  1. Sử dụng i:Interaction.Triggers và viết một Behavior

thí nghiệm này giảm ngắn trên thực tế tôi thấy không có cách nào để đính kèm hành vi tùy chỉnh của tôi để kiểm soát liên quan.

Đây là những gì XAML trông giống như:

<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> 

Và đây là hành vi tùy chỉnh:

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); 
    } 
} 

Đó không làm việc vì phân tích cú pháp XAML cần nó được gắn trực tiếp vào "MyControl "nhưng tôi cần phải đính kèm nó vào trình kích hoạt sự kiện. Sau đó tôi đã thử phương pháp này:

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)); 
    } 
} 

Điều này không thành công trên thực tế là lookupVisualParent không hoạt động. Cha mẹ hợp lý của hành vi luôn là null.

Tôi cho rằng đây là một nhiệm vụ khá phổ biến? Có một giải pháp tốt cho vấn đề này? Tôi thấy lạ khi tôi sẽ viết các lớp mô hình xem của mình để chúng lấy được từ DependencyObject để bắt đầu một hoạt ảnh khi một sự kiện cháy.

Cheers

Trả lời

4

Bạn chỉ có thể sử dụng một lá cờ: đặt một lá cờ trên VM của bạn được gọi là 'RecentlyChangedFlag'. Chuyển nó đến true, sau đó false, bất cứ khi nào (các) giá trị thích hợp thay đổi. Bạn có thể làm điều đó như sau:

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., với mã trên được đặt ChangedFlag = true khi bạn muốn báo hiệu hoạt ảnh bắt đầu. Nó sẽ được đặt lại thành false sau khi WPF truy vấn giá trị thực.

Sau đó, có hoạt ảnh xảy ra khi giá trị RecentlyChangedFlagtrue, làm ví dụ EnterAction.

Hy vọng điều đó sẽ hữu ích.

+0

Cảm ơn nhưng đó là cách tôi ban đầu "giải quyết" nó (bằng cách sử dụng một DataTrigger) nhưng, như tôi đã chỉ ra trong OP, đó là hacky. Tôi khá mới để WPF vì vậy nó có thể được điều này thực sự là cách bình thường của kích hoạt hành vi/hình ảnh động từ máy ảo nhưng với tôi điều này dường như được làm việc xung quanh một giới hạn mà không nên có. Nó có thể được rằng bạn chỉ đơn giản là không thể kích hoạt hình ảnh động từ các sự kiện trong VM? –

+0

Một ViewModel tồn tại để dịch một mô hình thành thứ gì đó mà chế độ xem có thể sử dụng. Như vậy đó là nơi hoàn hảo để làm những việc như thế này. Nó không phải là IMO hacky và một lá cờ chỉ ra rằng một cái gì đó quan trọng đã thay đổi nên tồn tại trong máy ảo. Vì vậy, miễn là ViewModel đứng lên trên riêng của mình, nó không phải là một vấn đề. Một ViewModel có một lá cờ để chỉ ra bất cứ điều gì 'sự kiện' mà bạn đang nói đến - nếu bạn gọi nó là điều đúng, nó có vẻ không quá đúng chỗ? –

+1

Tôi sẽ không tôn giáo về điều này, nhưng nó có vẻ kỳ lạ là nó không thể kích hoạt hình ảnh động từ các sự kiện. Sau khi tất cả, các sự kiện có để báo hiệu thay đổi trạng thái. Phải thêm một thuộc tính thứ hai chỉ để báo hiệu các thay đổi trạng thái cho thay đổi đầu tiên là IMHO giải pháp thay thế. Tôi ngạc nhiên khi thấy rằng các công cụ do WPF cung cấp là thiếu. Tôi chắc chắn có thể sống với "giải pháp sở hữu nhà nước" trong trường hợp cụ thể này nhưng tôi hình dung các lớp VM của tôi sẽ có đầy đủ các thuộc tính như vậy trong tương lai. Phải có một cách tốt hơn, phải không? –

Các vấn đề liên quan