5
\$\begingroup\$

So, I fixed my problem with a public ViewModel for my MainPage like this:

MainPage.xaml.cs:

private static MainPageVM Data = new MainPageVM();
public MainPage()
{
 this.InitializeComponent();
 SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;
 this.DataContext = Data;
 this.SizeChanged += (s, args) =>
 {
 PageSizeChanged();
 };
 Windows.Storage.ApplicationData.Current.DataChanged += (a, o) =>
 {
 CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
 {
 Data.Theme = (int)ApplicationData.Current.RoamingSettings.Values["Theme"];
 });
 };
}

MainPageVM.cs:

private void SetValues()
{
 if (Windows.Storage.ApplicationData.Current.RoamingSettings.Values.ContainsKey("Theme"))
 {
 int value = (int)Windows.Storage.ApplicationData.Current.RoamingSettings.Values["Theme"];
 if (value >= 0 && value <= 2) { Theme = value; }
 else { Theme = 0; }
 }
 else { Theme = 0; }
}
private int _theme = 0;
public int Theme
{
 get { return _theme; }
 set
 {
 if (value == _theme) return;
 _theme = value;
 OnPropertyChanged();
 }
}

Settings.xaml.cs:

private void InitSettings()
{
 if (Windows.Storage.ApplicationData.Current.RoamingSettings.Values.ContainsKey("Theme"))
 {
 int value = (int)Windows.Storage.ApplicationData.Current.RoamingSettings.Values["Theme"];
 if (value >= 0 && value <= 2) { Theme.SelectedIndex = value; }
 else { Theme.SelectedIndex = 0; }
 }
 else { Theme.SelectedIndex = 0; }
}
private void ThemeChanged(object sender, SelectionChangedEventArgs e)
{
 ApplicationData.Current.RoamingSettings.Values["Theme"] = Theme.SelectedIndex;
 ApplicationData.Current.SignalDataChanged();
}

Settings.xaml:

 <StackPanel>
 <TextBlock FontSize="15" Margin="0,5">Text and background color:</TextBlock>
 <ComboBox Name="Theme" SelectionChanged="ThemeChanged">
 <ComboBoxItem Content="Black on White/Purple" Foreground="Black" Background="White"/>
 <ComboBoxItem Content="White on Black/White" Foreground="White" Background="Black"/>
 <ComboBoxItem Content="Black on White/Gold" Foreground="Black" Background="White"/>
 </ComboBox>
 </StackPanel>
</StackPanel>

There is similar code for each setting, but this is a good representation of it. It doesn't feel right to use an int to represent my theme; should this be an enum? Please tell me all the problems now so I don't have to refactor again later.

asked Jan 18, 2015 at 0:19
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

I don't really like the dependencies on all that static stuff. It effectively means your code becomes very hard to test.

Also this code:

if (Windows.Storage.ApplicationData.Current.RoamingSettings.Values.ContainsKey("Theme"))
{
 int value = (int)Windows.Storage.ApplicationData.Current.RoamingSettings.Values["Theme"];
 if (value >= 0 && value <= 2) { Theme = value; }
 else { Theme = 0; }
}
else { Theme = 0; }

seems repeated and should be consolidated into a single method.

I'd start cleaning it up by introducing an IThemeProvider which can be injected into your MainPage, MainPageVM and Settings classes. Would probably look like this:

class ThemeChangedEventArgs : EventArgs
{
 public readonly int NewTheme;
 public ThemeChangedEventArgs(int newTheme)
 {
 NewTheme = newTheme;
 }
}
interface IThemeProvider
{
 int GetCurrentTheme();
 void SetCurrentTheme(int theme);
 event EventHandler<ThemeChangedEventArgs> ThemeChanged;
}

Then your MainPage would look something like this:

private MainPageVM Data = new MainPageVM();
private IThemeProvider _ThemeProvider;
public MainPage(IThemeProvider themeProvider)
{
 _ThemeProvider = themeProvider;
 this.InitializeComponent();
 SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;
 this.DataContext = Data;
 this.SizeChanged += (s, args) => PageSizeChanged()
 _ThemeProvider.ThemeChanged += (s, e) => Data.Theme = e.NewTheme;
}

MainPageVM:

private IThemeProvider _ThemeProvider; 
public MainPageVM(IThemeProvider themeProvider)
{
 _ThemeProvider = themeProvider;
}
private void SetValues()
{
 Theme = _ThemeProvider.GetCurrentTheme();
}

and Settings:

private IThemeProvider _ThemeProvider; 
public Settings(IThemeProvider themeProvider)
{
 _ThemeProvider = themeProvider;
}
private void InitSettings()
{
 Theme.SelectedIndex = _ThemeProvider.GetCurrentTheme();
}
private void ThemeChanged(object sender, SelectionChangedEventArgs e)
{
 _ThemeProvider.SetCurrentTheme(Theme.SelectedIndex);
}

Code looks a lot cleaner now I'd say and you can easily mock the IThemeProvider out and test it.

Implementation of the provider could be like this (based on what you currently do):

public class ApplicationDataThemeProvider : IThemeProvider
{
 public ApplicationDataThemeProvider()
 {
 Windows.Storage.ApplicationData.Current.DataChanged += (a, o) =>
 {
 CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
 {
 OnThemeChanged((int)ApplicationData.Current.RoamingSettings.Values["Theme"]);
 });
 };
 }
 public int GetCurrentTheme()
 {
 if (Windows.Storage.ApplicationData.Current.RoamingSettings.Values.ContainsKey("Theme"))
 {
 int value = (int)Windows.Storage.ApplicationData.Current.RoamingSettings.Values["Theme"];
 return (value >= 0 && value <= 2) ? value : 0;
 }
 return 0;
 }
 public void SetCurrentTheme(int theme)
 {
 ApplicationData.Current.RoamingSettings.Values["Theme"] = theme;
 ApplicationData.Current.SignalDataChanged();
 }
 public event EventHandler<ThemeChangedEventArgs> ThemeChanged;
 private void OnThemeChanged(int newTheme)
 {
 var handler = ThemeChanged;
 if (handler != null)
 {
 handler(this, new ThemeChangedEventArgs(newTheme));
 }
 }
}

This encapsulates all the nasty global app data stuff in a single class where it should be a lot easier to handle and debug.

answered Jan 18, 2015 at 18:44
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.