2011-07-11 5 views
3

私の目標は、ユーザーが設定ファイルを選択し、設定が読み込まれ、それに応じてUIが更新されることです。節約も明らかに可能でなければならない。"設定"オブジェクトの逆シリアル化でWPF UIを更新する方法

私のプログラムは現在WPF/XAMLではありません。これを実行すると、新しい設定が必要なときに多くの繰り返しが行われ、作業が追加されます。

誰かが私にWPF/XAMLが行く方法だと言いました。私はそれを見て、気に入っていましたが、私が望むことをやり遂げる方法はまだ分かりません。 WPF/XAMLの利点はもちろんデータバインディングですが、設定ファイル全体を読みたい場合は、古い設定オブジェクトを新しいものに置き換えることになります。 WPFプログラムがこれに反応し、指定されたデータバインディングに従ってフィールドを更新することはできますか?

私は、これが良いデザインであるかどうかに関心があります。

+0

データバインディングはずっと前から存在していましたwpf/xaml - *個人的に*スタック間を移動する "設定"がもっと必要なのですが... –

答えて

2

もちろん可能です。まず、設定オブジェクトはINotifyPropertyChangedインターフェイスを実装する必要があります。これは基本的に、プロパティセッターを呼び出すたびに呼び出されるイベントを追加します。そうすることで、依存性のないプロパティへのバインドが両方向で機能します。あなたは本当にそのインターフェースを必要としません。しかし、最初のセット(すべてのプロパティが読み取られている)がUIに反映された後に変更を行うには、そのインターフェイスが必要です。

私は通常、あなたの設定は今、そのクラスから派生しなければならないこと

public class PropertyChangedNotifier : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged 
    { 
     add { mPropertyChanged += value; } 
     remove { mPropertyChanged -= value; } 
    } 

    protected virtual void RaisePropertyChanged(string aPropertyName) 
    { 
     PropertyChangedEventHandler handler = mPropertyChanged; 
     if (handler != null) 
     { 
      var e = new PropertyChangedEventArgs(aPropertyName); 
      handler(this, e); 
     } 
    } 

    private PropertyChangedEventHandler mPropertyChanged; 
} 

の基本クラスを使用します。

class MySettings : PropertyChangedNotifier 
{ 
public string UserName 
{ 
    get{return mUserName;} 
    set{mUserName=value; RaisePropertyChanged("UserName");} 
} 
} 

uiの場合、DataBindingは常にDataContextに関連付けられます。

<Window 
    x:Class="MyApp.MainWindow"> 

<StackPanel> 
    <TextBox Text="{Binding UserName}"/> 
</StackPanel> 

</Window> 

テキストボックスは、プロパティ "UserName"から現在のセットdatacontextからその値を取得しようとします。 DataContextを設定するには、メインウィンドウのコードの中でそれを行うことができます。

public MainWindow() 
{ 
    InitializeComponent(); 
    DataContext = ReadMyUserSettings(); 
} 

いつでもDatacontextを変更すると、uiは自動的に更新されます。 そして、テキストボックスへの変更が設定に書き戻されます。何らかのキャンセルやワークフローの保存を追加することでこれを改善することもできます。その結果、ユーザーがキャンセルした場合に設定が変更されることはありません。そのためにはIEditableObjectBindingGroupを参照してください。

希望はあなたに大まかなアイデアをもたらします。

0

ここでは、MVVMパターンを使用したC#のような擬似コードの非常に単純な例を使って、これを行う方法を説明します。

まず、自分の設定を定義し、シリアル化/逆シリアル化されたモデルを定義します。私はNetDataContractSerializerを使ってこれを行うのが好きです。

[DataContract] 
public sealed class Person 
{ 
    [DataMember] 
    public string Name {get;set;} 
    [DataMember] 
    public int Age {get;set;} 
} 

私のViewModelは私もICommand読み込みと設定を保存するために持っているでしょう私のViewModelではこの構成の現在のインスタンス

public sealed class ViewModel : DependencyObject 
{ 
    #region Person 
    /// <summary> 
    /// The <see cref="DependencyProperty"/> for <see cref="Person"/>. 
    /// </summary> 
    public static readonly DependencyProperty TextProperty = 
     DependencyProperty.Register(
      PersonPropertyName, 
      typeof(Person), 
      typeof(ViewModel), 
      new UIPropertyMetadata(null)); 

    /// <summary> 
    /// The name of the <see cref="Person"/> <see cref="DependencyProperty"/>. 
    /// </summary> 
    public const string PersonPropertyName = "Person"; 

    /// <summary> 
    /// The Person 
    /// </summary> 
    public string Person 
    { 
     get { return (Person)GetValue(PersonProperty); } 
     set { SetValue(PersonProperty , value); } 
    } 
    #endregion  

    // snip 

を保持している公共の財産を持っているでしょう。CanExecuteExecuteの実行をViewModelに委譲するICommandの共通実装に関する多くの疑問があります。

ViewModelを使用して、コンフィグレーションモデルのパブリックプロパティにバインドするだけです。

<Window x:Class="Herp.DerpWindow" SnipXamlForBrevity="true"> 
    <Window.DataContext> 
    <ViewModel xmlns="clr-namespace:Herp" /> 
    </Window.DataContext> 
    <!-- and later... --> 
    <Label>The Person in Question:</Label> 
    <TextBlock Text="{Binding Person.Name}" /> 
    <Label>Age</Label> 
    <TextBlock Text="{Binding Person.Age}" /> 

あなたはUIが自動的に新しい値で更新され、それに取って代わるような構成モデルは、ViewModelにの公共のDependencyPropertyに保持されているので。もちろん、バインディング更新のUIを通知する代わりの方法としてINotifyPropertyChangedを使用することはできますが、私はそれを簡単に保つことを好みます。

関連する問題