2016-09-23 2 views
0

저는 C#의 초보자이며 MSDN 블로그의 INotifyPropertyChanged Event Handler에 대해 읽고 "stackoverflow"에서 검색했습니다. 하지만 실제로 코드에서 구현하는 방법과 이벤트와 속성을 함께 바인딩해야하는 방법을 이해하지 못합니다.Cant가 INotifyPropertyChanged 구현을 이해합니다.


는 이미 INotifyPropertyChangedBindingClass을 만들었습니다 그리고 코드는 다음과 같습니다

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

<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 및 코드 숨김 파일 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(); 
     } 
    } 
    } 
} 

이미 LocalSettingsFolder에서 응용 프로그램의 설정을 변경하려면 int notifySettings을 사용하고 있습니다 및 응용 프로그램의 모든 시간은 App.xaml의 설정을로드 다시 시작합니다. 설정을 변경할 때마다 다른 class에서 함수를 호출하고 설정을 변경하고 을 SettingsPage.xaml에 두 개 클릭하면 설정이 변경되고 animation이 재생됩니다. 이것은 오래된 방법입니다.
이제는 Theme Settings이 업데이트 될 때마다 및 PopupText 애니메이션을 재생할 필요가 없도록 이러한 이벤트를 함께 바인딩해야합니다. 이것이 내가 INotifyPropertyChanged Event에 대해 배울 수있는 방법입니다.
int notifySettingsint 값을 전달하여 그에 따라 설정을 변경합니다. 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")과 동일합니다. 그러나 속성은 굴절자를 안전하게 만듭니다.

질문의 나머지 부분에 대해서 : 나는 그 질문 자체가 너무 가져 왔고 적어도 하나 이상의 윤곽으로 구성되어 있다는 것을 알고 있습니다. 일단 propertychanged 부분을 고치면 특정 문제에 대한 새로운 질문을하게됩니다.

+0

다른 곳에서'SettingProperty'를 업데이트해야합니까? 아니면'_setting'의 값을 전달해야합니까? – Ahmar

+0

@Ahmar SettingProperty. 그것은 분명히 _setting에 대한 통지를 변경하지 않습니다. 당신이 _setting을 direchtly 업데이트하고 싶다면, 나중에 수동으로'OnPropertyChanged (nameof (SettingProperty));'를 호출하십시오. – CSharpie

+0

감사합니다.'OnPropertyChanged()'가 실제로 작동하지 않아서'value'가 제거되었습니다. – Ahmar

1

나는 설명하는 데 최선이 아니므로, 그 요점을 알기를 바랍니다. 나는 또한 그것을 제대로 테스트 할 시간이 없었지만,이 일을해야합니다.

+= 구문을 통해 이벤트에 가입 할 수 있습니다. 이제는 이벤트가 발생할 때마다 모든 구독자가 주어진 인수로 해고됩니다. 이 경우 PropertyChangedEventArgs의 인스턴스입니다.이렇게하면 가입자가 주어진 EventArgs의 값에 따라 다르게 행동 할 수 있습니다. EventArgs의 빈 인스턴스를 가입자에게 전달하여 가입자가 EventArgs의 값을 기반으로 아무 것도하지 않음을 의미합니다.

일부 사소한 변경 :

  • 추가 된 테마에 대한 열거. 선택한 테마를 확인할 때 형식 안전성을 추가합니다. 이것은 하드 코딩 된 문자열을 검사하는 것보다 낫습니다.

  • ThemeSetting을 찾을 수없는 경우 예외가 추가되었습니다. 그에 따라 try/catch 블록에서 예외를 처리 할 수 ​​있습니다. 하드 코딩 된 문자열을 확인하는 것보다 낫습니다.

  • appsetting 키에 const 문자열이 추가되었습니다. 이것은 이전 두 점과 마찬가지로 오타로 인한 런타임 오류를 예방하고 값을 관리 할 수있는 중심적인 장소를 제공합니다. 당신이 그것의 이름을 통과해야하므로

    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 setter에서 OnPropertyChanged()를 과소 평가하는 오류 코드가 발생하지 않도록 if (_setting! = value) 체크를 추가해야합니다. – SledgeHammer

+0

귀하의 답변에 상기 변경 사항을 구현했지만 작동하지 않습니다. 테마 설정이 변경 되더라도 애니메이션은 실행되지 않습니다. – Ahmar

+0

구현이 잘못되었습니다. OnPropertyChangedEventArgs에는 전달 된 속성의 이름이 필요하며 임의의 값은 필요하지 않습니다. 왜 그것의 구현은 CallerMemberName과 선택적 문자열을 사용합니다. 이 OnPropertyChanged()처럼 호출하십시오. – CSharpie

관련 문제