2011-07-11 60 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,數據綁定總是與設定DataContext

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

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

</Window> 

該文本框將嘗試從屬性「用戶名」的當前設置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;} 
} 

我的視圖模型將有保存這個配置的當前實例

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 

在我ViewModel我也有一個ICommand用於加載和保存配置的公共財產。這裏有很多關於ICommand的常見實現的問題,它將CanExecuteExecute的執行委託給ViewModel。

在您的UI中,您只需通過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}" /> 

因爲配置模型在視圖模型的一個公共的DependencyProperty舉行,當你更換的UI與新值自動更新。當然,您可以使用INotifyPropertyChanged作爲通知綁定更新UI的替代方法,但我更願意保持簡單。