2016-02-22 93 views
0

我需要在通用Windows應用程序的運行時更改應用程序的TextBlocks的顏色。更新通用Windows應用程序中的資源XAML

通用的Windows應用程序不支持動態資源使用樣式

<Style x:Key="MyText" TargetType="TextBlock"> 
    <Setter Property="Foreground" Value="{StaticResource TextColor}" /> 
</Style> 

我的問題是我一直在探索失敗的幾個不同的方法來改變TextBlock的

<TextBlock Text="Test" Style="{StaticResource MyText}"/> 

的顏色: 如何在運行時更改TextBlock的顏色?

接下來是所有試圖改變顏色:


起初,我也跟着這篇文章+視頻Dynamically Skinning Your Windows 8 App和我存儲TextColor在一個單獨的字典文件,我可以換入或換出MergedDictionaries

  • Day.xaml包含<SolidColorBrush x:Key="TextColor" Color="#FFDDEEFF" />
  • Night.xaml包含<SolidColorBrush x:Key="TextColor" Color="#FFFFDD99" />

在代碼:

ResourceDictionary _nightTheme = new ResourceDictionary() { Source = new Uri("ms-appx:///Themes/Night.xaml") }; 
    ResourceDictionary _baseTheme = new ResourceDictionary() { Source = new Uri("ms-appx:///Themes/MyApp.xaml") }; 

// OnLaunched - I set a default theme to prevent exceptions 
    Application.Current.Resources.MergedDictionaries.Add(_dayTheme); 

// Method that changes theme: 
     if (NightFall) 
     { 
      Application.Current.Resources.MergedDictionaries.Remove(_dayTheme); 
      Application.Current.Resources.MergedDictionaries.Add(_nightTheme); 
     } 
     else 
     { 
      Application.Current.Resources.MergedDictionaries.Remove(_nightTheme); 
      Application.Current.Resources.MergedDictionaries.Add(_dayTheme); 
     } 

當這個沒有工作,我想我需要明確的字典:

ResourceDictionary _baseTheme = new ResourceDictionary() { Source = new Uri("ms-appx:///Themes/MyApp.xaml") }; 
// Method that changes theme: 
     Application.Current.Resources.MergedDictionaries.Clear(); 
     Application.Current.Resources.MergedDictionaries.Add(_baseTheme); 
     if (NightFall) 
     { 
      Application.Current.Resources.MergedDictionaries.Add(_nightTheme); 
     } 
     else 
     { 
      Application.Current.Resources.MergedDictionaries.Add(_dayTheme); 
     } 

我也試着在更改字典的方法中刷新幀,無效

 var frame = Window.Current.Content as Frame; 
     frame.Navigate(frame.Content.GetType()); 

在另一個嘗試我試圖創建一個字典,運行和更新

ResourceDictionary _dynamicTheme = new ResourceDictionary(); 
// OnLaunched 
     _dynamicTheme.Add("TextColor", new SolidColorBrush(Windows.UI.Colors.Chocolate)); 
     Application.Current.Resources.MergedDictionaries.Add(_dynamicTheme); 
// Method that changes theme 
     _dynamicTheme.Remove("TextColor"); 
     _dynamicTheme.Add("TextColor", new SolidColorBrush(NightFall ? Windows.UI.Colors.Chocolate : Windows.UI.Colors.Cornsilk)); 

最後,我意識到,也許StaticResource使顏色不變的,所以我決定試試ThemeResource。我修改我的主題:

<Style x:Key="MyText" TargetType="TextBlock"> 
    <Setter Property="Foreground" Value="{ThemeResource MyTextColor}" /> 
</Style> 

Day.xaml

<ResourceDictionary.ThemeDictionaries> 
    <ResourceDictionary x:Key="Default"> 
     <SolidColorBrush x:Key="MyTextColor" Color="#FFDDEEFF" /> 
    </ResourceDictionary> 
</ResourceDictionary.ThemeDictionaries> 

Night.xaml

<ResourceDictionary.ThemeDictionaries> 
    <ResourceDictionary x:Key="Default"> 
     <SolidColorBrush x:Key="MyTextColor" Color="#FFFFDD99" /> 
    </ResourceDictionary> 
</ResourceDictionary.ThemeDictionaries> 

我換的方式進出Application.Current.Resources.MergedDictionaries的就像在以前的嘗試。 同樣,顏色沒有變化,即使我假刷新Frame

回答

1

我面臨同樣的問題,幾個月前,我不能,直到我遇到下列blog post它提出來解決這個問題一個很好的通用解決方案。

基本上你需要做的是:

首先

添加以下幫手Frame類,它將取代默認Frame

public class ThemeAwareFrame : Frame 
{ 
    private static readonly ThemeProxyClass _themeProxyClass = new ThemeProxyClass(); 

    public static readonly DependencyProperty AppThemeProperty = DependencyProperty.Register(
     "AppTheme", typeof(ElementTheme), typeof(ThemeAwareFrame), new PropertyMetadata(default(ElementTheme), (d, e) => _themeProxyClass.Theme = (ElementTheme)e.NewValue)); 


    public ElementTheme AppTheme 
    { 
     get { return (ElementTheme)GetValue(AppThemeProperty); } 
     set { SetValue(AppThemeProperty, value); } 
    } 

    public ThemeAwareFrame(ElementTheme appTheme) 
    { 
     var themeBinding = new Binding { Source = _themeProxyClass, Path = new PropertyPath("Theme"), Mode = BindingMode.OneWay }; 
     SetBinding(RequestedThemeProperty, themeBinding); 
     AppTheme = appTheme; 

    } 
    sealed class ThemeProxyClass : INotifyPropertyChanged 
    { 
     private ElementTheme _theme; 

     public ElementTheme Theme 
     { 
      get { return _theme; } 
      set 
      { 
       _theme = value; 
       OnPropertyChanged(); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     private void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

ThemeAwareFrame類作爲背後的想法博客文章作者解釋:

我創建了一個只用於存儲當前主題的代理類,如果主題發生更改,則傳播該代理類。它是一個靜態字段,因此 與所有ThemeAwareFrame共享。

我添加一個AppTheme依賴屬性。當它將被改變時, 將在代理類中改變。

在ThemeAwareFrame構造函數中,我將ThemeRequested屬性 綁定到代理類Theme屬性。

創建黑暗主題資源在App.xaml中

<Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary> 
       <ResourceDictionary.ThemeDictionaries> 
        <ResourceDictionary x:Key="Dark"> 
         <SolidColorBrush x:Key="MyTextColor" Color="DarkGray" /> 
        </ResourceDictionary> 
        <ResourceDictionary x:Key="Light"> 
         <SolidColorBrush x:Key="MyTextColor" Color="White" /> 
        </ResourceDictionary> 
       </ResourceDictionary.ThemeDictionaries> 
      </ResourceDictionary> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Application.Resources> 

在App.Xaml.cs改變rootFrame到ThemeAwareFrame,而不是一個簡單的框架:

rootFrame = new ThemeAwareFrame(ElementTheme.Dark); 
OnLaunched方法

 protected override void OnLaunched(LaunchActivatedEventArgs e) 
    { 
    #if DEBUG 
     if (System.Diagnostics.Debugger.IsAttached) 
     { 
      this.DebugSettings.EnableFrameRateCounter = true; 
     } 
    #endif 
     Frame rootFrame = Window.Current.Content as Frame; 

     // Do not repeat app initialization when the Window already has content, 
     // just ensure that the window is active 
     if (rootFrame == null) 
     { 
      // Create a Frame to act as the navigation context and navigate to the first page 
      rootFrame = new ThemeAwareFrame(ElementTheme.Dark); 
      // TODO: change this value to a cache size that is appropriate for your application 
      rootFrame.CacheSize = 1; 

      if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 
      { 
       // TODO: Load state from previously suspended application 
      } 
    //.. 

第四

使用ThemeResource代替staticResource使用Theme相關資源時:

<Page.Resources> 
    <Style x:Key="MyText" TargetType="TextBlock"> 
     <Setter Property="Foreground" Value="{ThemeResource MyTextColor}" /> 
    </Style> 
</Page.Resources> 

<Grid > 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*"/> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
    </Grid.RowDefinitions> 
    <TextBlock Text="Test" Style="{StaticResource MyText}" VerticalAlignment="Center" HorizontalAlignment="Center"/> 
    <Button Content="Dark Theme" Click="ChangeThemeToDarkClick" Grid.Row="1"></Button> 
    <Button Content="Light Theme" Click="ChangeThemeToLightClick" Grid.Row="2"></Button> 
</Grid> 

最後

要改變你的應用程序只需主題更改rootFrame像這樣的AppTheme屬性:

private void ChangeThemeToLightClick(object sender, RoutedEventArgs e) 
    { 
     (Window.Current.Content as ThemeAwareFrame).AppTheme = ElementTheme.Light; 
    } 

    private void ChangeThemeToDarkClick(object sender, RoutedEventArgs e) 
    { 
     (Window.Current.Content as ThemeAwareFrame).AppTheme = ElementTheme.Dark; 
    } 
相關問題