1

最近、DataBindingの実験を開始し、カスタムクラスにDependencyPropertiesを実装しました。それはすべてうまく機能し、可能性はエキサイティングですが、クラス全体の設計をわずかに変更することによってのみ解決できる可能性がある問題に遭遇しました。そして、これが唯一の選択肢であり、何も見逃していないことを確認したいと思います。

したがって、私のクラスには、ユーザーがアプリケーションにインポートしたビデオファイルに関する情報が格納されます。他のプロパティの中で、それは含まれています:

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

}

そのため、FilePathをDependencyPropertyに正常に置き換えました。ただし、UIでは、ほとんどの場合、ファイル名のみを表示したいと考えています。ファイル名は、値を提供するためにいくつかのロジックを使用しています。私の知る限り、ここに私の選択肢があります:

  1. FileNameとExtensionのDependencyPropertiesを作成し、コンストラクターでそれらの値を設定するだけで済みますが、それは冗長です。私はすでにFilePathにその情報を持っているので、このオプションを避けたいと思います。
  2. 1つはファイル名を表示するための1つ、もう1つは拡張子を表示するためのValueConvertersを作成し、それらをバインディングで使用します。

ValueConvertersに簡単に会っただけなので、よくわかりません。この目的で使用できますか?または、それらが存在する主な理由の1つに遭遇したことがありますか?:)

そして最後になりましたが、ValueConverterが正しい方法ではない場合、誰もがこれに似た状況を考えることができますか?私はそれらに直接飛び込むのを避けたいのですが、「その1つ」のプロパティはこのように表現できないため、機能しないことに気付くだけです。

4

3 に答える 3

1

これは必要ありませんDependencyPropertiesを使用してプロパティDependencyPropertyに設定する場合にのみ必要です。モデルクラスでこれを行っているとは思えません(Xamlでこのクラスを宣言しないためです)。MarkupExtension

はるかに軽量な方法は、を使用することINotifyPropertyChangedです。.NET3.5スタイルの実装は次のとおりです。

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

[CallerMemberName](.NET 4.5では、新しい属性のおかげでこれをいくらか簡略化できます。)

唯一の欠点は、プロパティにバッキングフィールドが必要なことです。ただし、この作業の一部を自動化し、明示的なバッキングプロパティの必要性を排除できるNotifyPropertyWeaverと呼ばれるVS拡張機能もあります。

于 2012-09-17T13:16:24.807 に答える
0

データを複製しないでください。

を優先Bindingします。これは、変更さIValueConverterれるたびに、UIでも更新されるためです。FilePathExtensionFileName

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これはPrismの一部であることに注意してください。ただし、を呼び出すことRaisePropertyChanged("FilePath")でそれなしで実行できます。プロパティの名前を変更するとコンパイル時エラーが発生するため、型の安全性を確保するのが適切です。

于 2012-09-17T12:53:52.303 に答える
0

私が理解している限り、UIにファイル名を表示したいだけです。次に、FilePath依存関係プロパティが変更されるたびにFileNameプロパティを更新することを検討できます(OnChangedFilePathメソッド)。ValidateFilePathメソッドでFilePathがOKかどうかを確認することもできます。FileNameは、依存関係プロパティまたはサポートするIPropertyChangedである必要があることに注意してください。そうでない場合、UIを変更しても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));
于 2012-09-17T13:08:18.770 に答える