2012-09-17 25 views
1

我最近开始尝试使用DataBinding并为我的自定义类实现DependencyProperties。这一切都正常工作,可能性是令人兴奋的,但是,我遇到了一个问题,可以通过略微修改整体课程设计来解决。我想确保这是唯一的选择,我不会错过任何东西。用依赖属性替换不平凡的getter

因此,我的班级存储有关用户导入到应用程序中的视频文件的信息。其中包括:

public class VideoFile { 

    public string FilePath { get; protected set; } 
    public uint ID { get; protected set; ] 
    public string Extension { get { return Path.GetExtension(FilePath); } } 
    public string FileName { get { return Path.GetFilename(FilePath); } } 

} 

所以,我已经用DependencyProperty成功替换了FilePath。但是,在用户界面中,我大多只想显示文件名,它使用一些逻辑来提供它的价值。据我所知,这里是我的选择:

  1. 我可以简单地创建一个文件名和扩展DependencyProperties,并在构造函数中设置自己的价值,但这是多余的;我在FilePath中已经有了这些信息,所以我想避免这个选项。
  2. 创建ValueConverters,一个用于显示文件名,另一个用于显示扩展名,并在我的绑定中使用它们。

我只是简单地遇到了ValueConverters,所以我不确定它。我可以将它们用于此目的吗?或者,我刚刚遇到他们存在的主要原因之一? :)

最后但并非最不重要,任何人都可以想到一个类似的情况,当一个ValueConverter不是正确的路要走吗?我想避免直接跳入它们,只是意识到它不会工作,因为“那一个”属性不能用这种方式表达。

+1

你为什么要将这些转换为'DependencyProperty'?我会从发布的代码中怀疑你并不需要。 –

+0

@DanPuzey,因为我想在UI中显示它们。更具体地说,一个列表框,每个项目表示这个类的一个实例。以缩略图,文件名,大小(MB)和持续时间(秒)为单位。虽然这些属性预计不会改变,但我想在各个地方展示它们,并且厌倦了编写循环和在代码中创建控件。我想要一个漂亮的,干净的XAML和一个摇摆的DataTemplate :) –

+0

你不需要'DependencyProperty'能够在UI中显示它们。事实上,我建议你应该避免这是一个不必要的开销。 (请参阅我的答案以获得替代方案。) –

回答

0

请勿复制数据。

身高BindingIValueConverter,因为这样一来,每当FilePath变化,ExtensionFileName会在UI和更新。

你也当然,提高PropertyChanged他们在FilePath的二传手,但是这是不好的做法,因为FilePath不应该去计较谁/什么使用它。

类则是这样的:

public class VideoFile : INotifyPropertyChanged { 

    string m_FilePath; 
    public string FilePath 
    { 
     get { return m_FilePath; } 
     protected set 
     { 
      if(value != m_FilePath) 
      { 
      m_FilePath = value; 
      RaisePropertyChanged(() => this.FilePath); 
      } 
     } 
    } 
    public uint ID { get; protected set; } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected void RaisePropertyChanged<T>(Expression<Func<T>> _PropertyExpression) 
    { 
     RaisePropertyChanged(PropertySupport.ExtractPropertyName(_PropertyExpression)); 
    } 

    protected void RaisePropertyChanged(String _Prop) 
    { 
     PropertyChangedEventHandler handler = this.PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(_Prop)); 
     } 
    } 

    #endregion 
} 

请注意,PropertySupport是棱镜的一部分,但是你可以通过调用RaisePropertyChanged("FilePath")离不开它,它干脆利落有型的安全,因为如果更改属性的名称你将有一个编译时错误。

+0

计算的属性不是数据的重复,而且转换器非常昂贵。我建议使用'PropertyChanged'更有意义,如果这个类是作为一个UI绑定模型。特别是,当'FilePath'发生变化时,除非您还实现了'INotifyPropertyChanged'或'DependencyProperty',否则UI将不会被任何*属性反弹。在这两者中,NotifyPropertyChanged更轻巧。 –

+0

是的,他确实需要实现INotifyPropertyChanged,但是使FilePath成为DependencyProperty也可以。而且calculatd的属性**绝对**是数据重复:这是相同的数据呈现不同。 –

+0

呈现不同但存储一次:这种类存在的原因。这就是为什么,例如'FileInfo'有多个属性来返回文件名的一部分。与使用转换器相比,它不会重复数据:它是相同的代码,封装方式不同。如果您建议他将'FilePath'作为'DependencyProperty',则应该在代码中包含该实现。 –

0

就我所知,您只想在用户界面上显示文件名。然后,只要FilePath依赖项属性发生更改(OnChangedFilePath方法),您就可以考虑更新FileName属性。您还可以在ValidateFilePath方法中检查FilePath是否正确。请注意,FileName必须也是依赖项属性或支持IPropertyChanged,否则在更改UI时不会更新它。您不需要为此使用转换器。

public string FilePath 
{ 
    get { return (string)GetValue(FilePathProperty); } 
    set { SetValue(FilePathProperty, value); } 
} 

private static object CoerceFilePath(DependencyObject d, object value) 
{ 
    return value; 
} 

private static bool ValidateFilePath(object Value) 
{ 
    return true; 
} 

private static void OnChangedFilePath(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
} 

public static readonly DependencyProperty FilePathProperty = 
    DependencyProperty.Register("FilePath", typeof(string), typeof(ClassName), 
    new PropertyMetadata(@"C:\File.avi", OnChangedFilePath, CoerceFilePath), 
    new ValidateValueCallback(ClassName.ValidateFilePath)); 
+0

这不是我正在寻找的,但它给了我一些与这个问题无关的东西的一些想法,所以非常感谢:) –

1

你不需要DependencyProperties这个。你只需要一个DependencyProperty当你打算将设置为属性使用MarkupExtension,我怀疑你是用模型类来做这件事(因为你不会在Xaml中声明这个类!)。

更轻巧的方法是使用INotifyPropertyChanged。这里有一个.NET 3.5风格的实现:(在.NET 4.5本可以有所简化得益于新[CallerMemberName]属性)

public class VideoFile : INotifyPropertyChanged 
{ 
    private string _filePath; 

    public string FilePath 
    { 
     get 
     { 
      return _filePath; 
     } 
     protected set 
     { 
      _filePath = value; 
      OnPropertyChanged("FilePath"); 
      OnPropertyChanged("Extension"); 
      OnPropertyChanged("FileName"); 
     } 
    } 

    public uint ID { get; protected set; } 
    public string Extension { get { return Path.GetExtension(FilePath); } } 
    public string FileName { get { return Path.GetFileName(FilePath); } } 

    protected void OnPropertyChanged(string propName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

唯一的缺点是,你需要为你的属性支持字段。但是,有一个叫做NotifyPropertyWeaver的VS扩展可以自动完成这部分工作,并且也不需要显式的支持属性。

+0

这是很好的,直到你有几个属性提高PropertyChanged对其他属性,那么你可以'不知道设置什么东西会导致头部或尾部的故障,这是调试的噩梦。这就是为什么我反对它的原因。 –

+0

感谢您的详细实施,并且支持字段不是问题。不过,我仍然认为我需要一个依赖属性。据我所知,以这种方式实现它将保持UI自动调整,所以当我说Label1.Content = VideoFile1.FileName时,一旦属性发生变化,标签就会更新。但是我在XAML中声明了一个列表框,并且在该列表框中,我想为列表项目编写自定义DataTemplate。在该模板中,我想创建标签和图像,并将它们绑定到这些属性上......并且我认为这在这种情况下无法帮助我。我错了吗? –

+1

你错了。 'INotifyProperyChanged'是您自动更新用户界面所需的全部功能,包括自定义的'DataTemplate'。一个'DependencyProperty'可以工作,但对于这个用途来说是过分的。和@Baboon:'PropertyChanged'如何比'DependencyProperty'更难调试? –