2013-01-10 32 views
2

在我的一个WPF项目中,我在XAML中创建了动画故事板,该动画故事板的计时属性可以在开始动画之前动态更改。由于我需要一种方法来改变代码中的值,我将它们绑定到类的属性上。是否有一种很好的方法将xaml绑定到依赖于多个其他属性的属性?

的基本想法是,有两个阶段的动画,故事板我用ObjectAnimationUsingKeyFrames这需要总的动画时间,所以我有属性,像这样:

public TimeSpan RaiseTime { get; set } 

public TimeSpan FallTime { get; set; } 

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

当动画第一创建,它正确地从这些属性获取值,但由于它们可以动态更改,我需要一种方法来通知XAML值已更改。

很容易将RaiseTime和FallTime转换为DependencyPropertys,以便它们的更改将反映在XAML绑定中,但TotalTime又如何?它本身没有价值,所以我不能把它变成DP。

Yesturday我花了几个小时搜索/尝试随机的东西,试图让这个工作,并最终得到了一些工作使用MultiBinding既RaiseTime和FallTime和IMultiValueConverter,感谢几个SO问题和博客文章: Bind an element to two sources http://blog.wpfwonderland.com/2010/04/15/simplify-your-binding-converter-with-a-custom-markup-extension/

我的问题是:这真的是最好的办法吗?对我来说,似乎(至少)这样一个简单的任务,但它需要很多(主要是样板)代码来工作。我认为必须有一种更简单,不那么冗长的绑定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)。之后,OnRaiseTimeChangedOnFallTimeChanged将保持更新TotalTime

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 
} 
相关问题