2016-09-23 77 views
0

我只是C#中的一個新手,我在MSDN博客上閱讀INotifyPropertyChanged Event Handler並在這裏搜索「stackoverflow」。但我真的不明白如何在代碼中實現它,以及如何將事件和屬性綁定在一起。
不能理解INotifyPropertyChanged的實現

我已經與INotifyPropertyChanged取得了BindingClass,代碼爲:

namespace Testing.Pages 
{ 
    class BindingClass : INotifyPropertyChanged 
    { 
    private string _setting; 
    public event PropertyChangedEventHandler PropertyChanged; 

    public BindingClass() 
    { 

    } 

    public BindingClass(string value) 
    { 
     _setting = value; 
    } 

    public string SettingProperty 
    { 
     get { return _setting; } 
     set 
     { 
      _setting = value; 
      // calling OnPropertyChanged whenever the property gets updated 

     } 
    } 

    protected void OnPropertyChanged([CallerMemberName] string _setting = "") 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(_setting)); 
    } 
    } 
} 


SettingsPage.xaml

<TextBlock x:Name="PopupText" 
       Grid.Row="0" 
       HorizontalAlignment="Center" 
       VerticalAlignment="Center" 
       Margin="0,0,0,20" 
       Text="Your theme will be updated next time you start the app." 
       TextWrapping="Wrap" 
       Visibility="Collapsed"> 
     <TextBlock.Resources> 
      <Storyboard x:Name="popup_animate"> 
       <DoubleAnimation Duration="0:0:2" 
           Storyboard.TargetName="PopupText" 
           AutoReverse="True" 
           From="0.0" 
           To="1.0" 
           BeginTime="{x:Bind }" 
           Storyboard.TargetProperty="(TextBlock.Opacity)" 
         ></DoubleAnimation> 
      </Storyboard> 
     </TextBlock.Resources> 
    </TextBlock> 
<TextBlock Text="Change Theme?" 
        Margin="10,10,0,0"></TextBlock> 
     <RadioButton x:Name="DarkTheme_btn" 
        Click="ChangeTheme_btn_Click" 
        Content="Dark Theme" 
        Margin="10,0,0,0" 
        GroupName="theme"></RadioButton> 
     <RadioButton x:Name="LightTheme_btn" 
        Click="ChangeTheme_btn_Click" 
        Content="Light Theme" 
        Margin="10,0,0,0" 
        GroupName="theme"></RadioButton> 

和代碼隱藏文件SettingsPage.xaml.cs是:

namespace Testing.Pages 
{ 

/// <summary> 
/// An empty page that can be used on its own or navigated to within a Frame. 
/// </summary> 
    public sealed partial class SettingsPage : Page 
    { 
    BindingClass notifyProperty = new BindingClass(); 

    public SettingsPage() 
    { 
     this.InitializeComponent(); 
     NavigationCacheMode = NavigationCacheMode.Enabled; 
    } 

    private void ChangeTheme_btn_Click(object sender, RoutedEventArgs e) 
    { 
     DataContext = notifyProperty; 
     int notifySettings = 0; 
     if ((bool)DarkTheme_btn.IsChecked) 
     { 
      notifySettings = 2; 
      AppSettings.saveThemeSettings(notifySettings); 
      PopupText.Visibility = Visibility.Visible; 
      popup_animate.Begin(); 
     } 
     else if ((bool)LightTheme_btn.IsChecked) 
     { 
      notifySettings = 1; 
      AppSettings.saveThemeSettings(notifySettings); 
      PopupText.Visibility = Visibility.Visible; 
      popup_animate.Begin(); 
     } 
    } 
    } 
} 

我已經使用了int notifySettings改變LocalSettingsFolder應用程序的設置和應用程序每次重新啓動在App.xaml加載設置。每當我更改設置時,我都會調用另一個class中的功能,並且它會更改設置,當我單擊SettingsPage.xaml中的這兩個radiobuttons中的一個時,將播放animation。這是舊的方法。
現在我想將這些事件綁定在一起,這樣我就不必使用int notifySettingsPopupText動畫,因爲它在每次更新Theme Settings時都會播放。這是我如何也可以瞭解INotifyPropertyChanged Event
int notifySettings通過一個int值來相應地更改設置。 1 = LightTheme和2 = DarkTheme。

這裏是Settings Class

namespace Testing.Pages 
{ 
    class AppSettings 
    { 
    public static void saveThemeSettings(int value) 
    { 
     ApplicationDataContainer themeSettings = ApplicationData.Current.LocalSettings; 
     StorageFolder localFolder = ApplicationData.Current.LocalFolder; 
     themeSettings.Values["AppThemeSetting"] = value.ToString(); 
    } 

    public static string readThemeSettings() 
    { 
     ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; 
     StorageFolder localFolder = ApplicationData.Current.LocalFolder; 
     string appSettingsString = "error, nothing found"; 
     if (localSettings.Values.ContainsKey("AppThemeSetting")) 
     { 
      appSettingsString = localSettings.Values["AppThemeSetting"]?.ToString(); 
     } 
     return appSettingsString; 
    } 

    public static void removeLocalSettings(string settingValue) 
    { 
     ApplicationData.Current.LocalSettings.Values.Remove(settingValue); 
    } 

    } 

} 

如果仍然有任何含糊之處,請讓我知道,我可以嘗試進一步解釋。我希望有人能幫助我。

更新:
我根據答案由丹尼Bogers但需要Animation不啓動,我認爲這是因爲該功能甚至不被稱爲修改了自己的項目。我做了一些更改並嘗試自行完成,但並沒有真正實現,所以我將使用自己的方法來進行更改,直到其他人提出解決方案。

+0

您發表評論'/ /每當屬性得到更新時調用OnPropertyChanged',您需要真正顯示代碼,或者您的真實代碼是否只有該評論? –

+0

我實際上從微軟博客獲得了代碼,我編輯了一下,它寫在那裏,所以我保留了它。但我需要知道如何一起實現這些功能。所以我可以瞭解它。 – Ahmar

回答

1

的的PropertyChanged需要知道哪些屬性更改,所以你必須通過它的名字。

使它看起來像這樣:

public string SettingProperty 
{ 
    get { return _setting; } 
    set 
    { 
     if(_setting != value) // Or String.Equals(_setting, value, ...) 
     { 
      _setting = value; 
      OnPropertyChanged(); // Invoke using no argument. 
     } 
    } 
} 

protected void OnPropertyChanged([CallerMemberName] string propertyName = "") 
{ 
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
} 

的OnPropertyChanged方法使用它的參數CallerMemberName屬性,該屬性也是可選的。這意味着編譯器將使用這個參數並將iith替換爲調用者的實際名稱。所以不要自己傳遞任何價值。

它相當於PropertyChanged("SettingProperty")。然而屬性使折射器安全。

關於你的問題的其餘部分:我相信這個問題本身帶來太多問題,並且包含至少一個以上的問題。所以一旦你修復了屬性改變的部分,而是問了一個具體問題的新問題。

+0

我是否需要從其他地方更新'SettingProperty'?或者我需要傳遞'_setting'的值? – Ahmar

+0

@Ahmar SettingProperty。它沒有注意到明顯的改變。如果你想直接更新_setting,然後手動調用'OnPropertyChanged(nameof(SettingProperty));'。 – CSharpie

+0

Thankyou,'OnPropertyChanged()'確實不是首先工作,並從它的工作中刪除'價值'。 – Ahmar

1

我不是最擅長解釋的東西,我希望你能得到它的要點! 我也沒有時間來正確地測試它,但是這應該可以完成這項工作。

您可以通過+=語法訂閱事件。現在,無論何時提出事件,所有訂戶都會被解僱。在這種情況下,一個PropertyChangedEventArgs的實例。這允許您的訂戶根據給定的EventArgs的值而行爲不同(您也可以將EventArgs的空實例傳遞給您的訂戶,這意味着您的訂戶不會根據EventArgs中的值進行任何操作)。

一些細微的變化:

  • 增加了對主題的枚舉。檢查選擇哪個主題時添加類型安全性。這比檢查硬編碼字符串要好。

  • 無法找到ThemeSetting時添加了異常。您可以在try/catch塊中相應地處理異常。這再次比檢查硬編碼字符串更好。

  • 爲您的應用程序密鑰添加了一個常量字符串。與前面兩點一樣,這將防止由於錯字造成的運行時錯誤/爲您提供一個集中位置來管理值。

    namespace Testing.Pages 
    { 
        public enum Themes 
        { 
         Light = 1, 
         Dark = 2 
        } 
    } 
    
    namespace Testing.Pages 
    { 
        public class ThemeSettingNotFoundException : Exception 
        { 
         public ThemeSettingNotFoundException() : base("error, nothing found") 
         { 
         } 
        } 
    
    } 
    
    namespace Testing.Pages 
    { 
        class BindingClass : INotifyPropertyChanged 
        { 
         private string _setting; 
         public event PropertyChangedEventHandler PropertyChanged; 
    
         public BindingClass() { 
    
         } 
    
         public BindingClass(string value) { 
          _setting = value; 
         } 
    
         public string SettingProperty 
         { 
          get { return _setting; } 
          set 
          { 
           if(!_setting.Equals(value)){ 
            _setting = value; 
            OnPropertyChanged(); 
           } 
          } 
         } 
    
         protected void OnPropertyChanged([CallerMemberName] string _setting = "") { 
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(_setting)); 
         } 
        } 
    } 
    
    
    namespace Testing.Pages 
    { 
    
        /// <summary> 
        /// An empty page that can be used on its own or navigated to within a Frame. 
        /// </summary> 
        public sealed partial class SettingsPage : Page 
        { 
         BindingClass notifyProperty = new BindingClass(); 
    
         public SettingsPage() { 
          this.InitializeComponent(); 
          NavigationCacheMode = NavigationCacheMode.Enabled; 
    
          //Subscribe to the PropertyChanged event 
          notifyProperty.PropertyChanged += OnThemeSettingChanged; 
         } 
    
         private void ChangeTheme_btn_Click(object sender, RoutedEventArgs e) { 
          DataContext = notifyProperty; 
          SaveThemeSettings(); 
         } 
    
         private void SaveThemeSettings() 
         { 
          var notifySettings = 0; 
          if ((bool)DarkTheme_btn.IsChecked) 
           notifySettings = 2; 
          else if ((bool)LightTheme_btn.IsChecked) 
           notifySettings = 1; 
    
          //Only save theme settings when a button was checked 
          if (notifySettings != 0) 
           AppSettings.saveThemeSettings((Themes)notifySettings); 
         } 
    
         private void OnThemeSettingChanged(object sender, PropertyChangedEventArgs args) 
         { 
          PopupText.Visibility = Visibility.Visible; 
          popup_animate.Begin(); 
         } 
        } 
    } 
    
    
    namespace Testing.Pages 
    { 
        class AppSettings 
        { 
         private const string ThemeSettingKey = "AppThemeSetting"; 
    
         public static void saveThemeSettings(Themes theme) { 
          ApplicationDataContainer themeSettings = ApplicationData.Current.LocalSettings; 
          themeSettings.Values[ThemeSettingKey] = theme.ToString(); 
         } 
    
         public static Themes readThemeSettings() { 
          ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; 
          if (!localSettings.Values.ContainsKey(ThemeSettingKey)) 
           throw new ThemeSettingNotFoundException(); 
          var appSettingsString = localSettings.Values[ThemeSettingKey]; 
          return (Themes)Enum.Parse(typeof(Themes), appSettingsString); 
         } 
    
         public static void removeLocalSettings(string settingValue) { 
          ApplicationData.Current.LocalSettings.Values.Remove(settingValue); 
         } 
        } 
    } 
    
+0

在你的SettingProperty設置器中,你應該添加一個if(_setting!= value)檢查來防止錯誤的代碼過調用OnPropertyChanged(),因爲這樣做代價昂貴。 – SledgeHammer

+0

我在你的答案中實現了所述更改,但它不起作用。即使主題設置被更改,動畫也不會運行。 – Ahmar

+0

實現是錯誤的,OnPropertyChangedEventArgs需要傳遞的屬性的名稱而不是一些任意的值。這就是爲什麼它的實現使用CallerMemberName和一個可選的字符串。只需像這樣調用'OnPropertyChanged()'。 – CSharpie

相關問題