2016-09-23 75 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

相关问题