2013-01-10 2 views
2

내 WPF 프로젝트 중 하나에서 애니메이션을 시작하기 전에 동적으로 변경 될 수있는 타이밍 속성이있는 XAML의 애니메이션 스토리 보드를 만들었습니다. 코드의 값을 변경하는 방법이 필요했기 때문에 클래스의 속성에 바인딩했습니다.다른 여러 속성에 의존하는 속성에 xaml을 바인딩하는 좋은 방법이 있습니까?

public TimeSpan RaiseTime { get; set } 

public TimeSpan FallTime { get; set; } 

public TimeSpan TotalTime 
{ 
    get { return RaiseTime + FallTime; } 
} 

애니메이션은 첫번째 경우 :

기본적인 아이디어는이 애니메이션에 두 단계가 있고, 스토리 보드에서 I는 전체 애니메이션 시간이 소요 ObjectAnimationUsingKeyFrames을 사용하기 때문에 내가 그렇게 같은 특성을 가지고 있었다 이 속성에서 값을 올바르게 가져 오지만 동적으로 변경할 수 있으므로 값이 변경되었음을 XAML에 알리는 방법이 필요합니다.

RaiseTime 및 FallTime을 DependencyPropertys로 변환하면 변경 사항이 XAML 바인딩에 반영되지만, TotalTime은 어떨까요? 가치 자체가 없으므로 DP로 전환 할 수 없습니다.

Yesturday 나는 몇 시간 동안 무작위로 검색하고 시도해 보았습니다. 몇 가지 SO 질문과 블로그 게시물 덕분에 RaiseTime과 FallTime 및 IMultiValueConverter 모두에 멀티 바인딩을 사용하여 작업 할 수있었습니다. Bind an element to two sources http://blog.wpfwonderland.com/2010/04/15/simplify-your-binding-converter-with-a-custom-markup-extension/

제 질문은 : 이것을 수행하는 가장 좋은 방법입니까? 그것은 (나 최소한 atleast) 그런 간단한 작업을 보이지만 아직 일을하기 위해서는 너무 많은 코드가 필요합니다. TotalTime을 바인딩하고 업데이트를 XAML로 푸는 더 간단하고 간략한 방법이 있어야한다고 생각했지만 아직 찾지 못했습니다. 거기에, 아니면 그냥 꿈꿔?

+0

IPropertyChanged를 구현하고 TotalTime에서 바인딩을 만들 수 있습니다. –

답변

4

INotifyPropertyChanged를 사용하여 확실히 작동시키고, 클래스에 간단하게 바인딩 할 수 있습니다.

이 같은 모양 코드 : (테스트되지 않은 코드)

public class PleaseChangeTheNameOfThisClass : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public void RaisePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    private TimeSpan _raiseTime; 
    public TimeSpan RaiseTime 
    { 
     get { return _raiseTime; } 
     set 
     { 
      if (_raiseTime != value) 
      { 
       _fallTime = value; 
       RaisePropertyChanged("RaiseTime"); 
       RaisePropertyChanged("TotalTime"); 
      } 
     } 
    } 

    private TimeSpan _fallTime; 
    public TimeSpan FallTime 
    { 
     get { return _fallTime; } 
     set 
     { 
      if (_fallTime != value) 
      { 
       _fallTime = value; 
       RaisePropertyChanged("FallTime"); 
       RaisePropertyChanged("TotalTime"); 
      } 
     } 
    } 

    public TimeSpan TotalTime 
    { 
     get { return RaiseTime + FallTime; } 
    } 
} 
+0

그건 재미 있어요. 나는 INotifyPropertyChanged에 대해 읽었지만 전에 DP 만 사용 했으므로 먼저 시도해 보았습니다. 나는 그것을 시도 할 것이다. – bj0

+0

두 방법을 모두 시도했지만 두 함수 모두 정상적으로 작동했지만이 방법은 명확하지 않았습니다. – bj0

1

그것은 여전히 ​​매우 상세 할 수 있지만 사실 DependencyProperties으로이 작업을 수행 할 수 있습니다

첨부 "는 onChanged을" RaiseTimeFallTime DP에 대한 콜백은 TotalTime DP를 업데이트하고 TotalTime은 읽기 전용입니다 (다른 DP 등록 구문 및 전용 설정자).

public TimeSpan RaiseTime 
{ 
    get { return (TimeSpan)GetValue(RaiseTimeProperty); } 
    set { SetValue(RaiseTimeProperty, value); } 
} 
public static readonly DependencyProperty RaiseTimeProperty = 
    DependencyProperty.Register("RaiseTime", typeof(TimeSpan), typeof(MainWindow), 
           new PropertyMetadata(TimeSpan.Zero, OnRaiseTimeChanged)); 

private static void OnRaiseTimeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
{ 
    var owner = sender as MainWindow; 
    owner.TotalTime = owner.RaiseTime + owner.FallTime; 
} 


public TimeSpan FallTime 
{ 
    get { return (TimeSpan)GetValue(FallTimeProperty); } 
    set { SetValue(FallTimeProperty, value); } 
} 
public static readonly DependencyProperty FallTimeProperty = 
    DependencyProperty.Register("FallTime", typeof(TimeSpan), typeof(MainWindow), 
           new PropertyMetadata(TimeSpan.Zero, OnFallTimeChanged)); 

private static void OnFallTimeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
{ 
    var owner = sender as MainWindow; 
    owner.TotalTime = owner.RaiseTime + owner.FallTime; 
} 


/// <summary> 
/// Read-only DP: 
/// http://msdn.microsoft.com/en-us/library/ms754044.aspx 
/// http://www.wpftutorial.net/dependencyproperties.html 
/// </summary> 
public TimeSpan TotalTime 
{ 
    get { return (TimeSpan)GetValue(TotalTimeProperty); } 
    private set { SetValue(TotalTimePropertyKey, value); } 
} 
public static readonly DependencyPropertyKey TotalTimePropertyKey = 
    DependencyProperty.RegisterReadOnly("TotalTime", typeof(TimeSpan), typeof(MainWindow), 
             new PropertyMetadata(TimeSpan.Zero)); 

public static readonly DependencyProperty TotalTimeProperty = TotalTimePropertyKey.DependencyProperty; 

기본값을 더해야합니다 (여기에는 0 + 0 = 0). 그 후에 OnRaiseTimeChangedOnFallTimeChangedTotalTime을 업데이트합니다.

0

나는 이것이 조금 더 간결하다고 생각한다. 최신 C#에서 제공되는 "CallerMemberName"을 참조하십시오.

public sealed class ViewModel : INotifyPropertyChanged 
{ 
    private TimeSpan _raiseTime; 
    private TimeSpan _fallTime; 

    public TimeSpan RaiseTime 
    { 
     get { return _raiseTime; } 
     private set 
     { 
      if (SetProperty(ref _raiseTime, value)) 
      { 
       OnPropertyChanged("TotalTime"); 
      } 
     } 
    } 

    public TimeSpan FallTime 
    { 
     get { return _fallTime; } 
     private set 
     { 
      if (SetProperty(ref _fallTime, value)) 
      { 
       OnPropertyChanged("TotalTime"); 
      } 
     } 
    } 

    public TimeSpan TotalTime 
    { 
     get { return RaiseTime + FallTime; } 
    } 

    #region Put these in a base class... 

    private bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null) 
    { 
     if (Equals(storage, value)) 
     { 
      return false; 
     } 

     storage = value; 
     OnPropertyChanged(propertyName); 
     return true; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    #endregion 
} 
관련 문제