【问题标题】:Updating ResourceTheme not reflecting on TextBox BorderBrush in UWP App更新 ResourceTheme 不反映在 UWP 应用程序中的 TextBox BorderBrush
【发布时间】:2019-02-23 05:18:24
【问题描述】:

我正在从代码隐藏更新 App ThemeResource。它正在更改应用程序主题,但 TextBox BorderBrush 属性未更新。

我有一个自定义资源 MyBorderBrush 用于 DarkLight 我在 App.xaml 中定义的主题。

Xaml:

<StackPanel>
            <TextBox PlaceholderText="My PlaceholderText" Height="100" Width="500" HorizontalAlignment="Center" Style="{StaticResource NoHighlightTextBoxStyle}" BorderBrush="{Binding IsError, Converter={ThemeResource BorderBrushColorConverter}}" VerticalAlignment="Center" ></TextBox>
            <Button Content="Change Theme" Click="Button_Click"></Button>
</StackPanel>

代码背后:

private void Button_Click(object sender, RoutedEventArgs e)
{
    this.RequestedTheme = this.RequestedTheme == ElementTheme.Light ? ElementTheme.Dark : ElementTheme.Light;
}

编辑

我认为问题可能出在背后的代码或定义资源上,因此我只共享了最少的代码以重现该问题。但正如@Ashiq 所指出的,问题出在TextBox 上。实际上,问题是我将BorderBrush 属性绑定到转换器以获得正确的值,但是在更改主题时边框颜色没有改变。

转换器:

 public class BorderBrushColorConverter : IValueConverter
 {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            var isError = value as bool? ?? false;
            return isError
                ? Application.Current.Resources["MyBorderBrushMandatory"] as SolidColorBrush
                : Application.Current.Resources["MyBorderBrush"] as SolidColorBrush;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
}

App.xaml

<ResourceDictionary x:Key="Light" >
             <Color x:Key="MyBorder">#6b6b6b</Color>
             <SolidColorBrush x:Key="MyBorderBrush" Color="{ThemeResource MyBorder}" />

              <Color x:Key="MyBorderMandatory">#ff0000</Color>
              <SolidColorBrush x:Key="MyBorderBrushMandatory" Color="{ThemeResource MyBorderMandatory}" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark" >
               <Color x:Key="MyBorder">#c85332</Color>
               <SolidColorBrush x:Key="MyBorderBrush" Color="{ThemeResource MyBorder}" />

               <Color x:Key="MyBorderMandatory">#FFD700</Color>
               <SolidColorBrush x:Key="MyBorderBrushMandatory" Color="{ThemeResource MyBorderMandatory}" />
</ResourceDictionary>

【问题讨论】:

  • 您是否使用 INotifyPropertyChanged 事件到 IsError 属性?
  • 是的,我使用 INotifyPropertyChanged 表示 IsError。

标签: c# xaml uwp


【解决方案1】:

您不应将 Brush 绑定到 TextBoxBorderBrush,这意味着您已将固定 Brush 值设置为 BorderBrush。当您在 xaml 中使用BindingIValueConverter 时,它会将“MyBorderBrushMandatory”或“MyBorderBrush”资源中的SolidColorBrush 值分配给BorderBrush,它是一个静态值,不会根据主题的改变。简而言之,类似将红色固定SolidColorBrush设置为BorderBrush,与动态主题资源无关。

如果您希望在更改主题时更改TextBoxBorderBrush,只需将您的xaml TextBox 绑定代码替换为主题资源参考:

<TextBox PlaceholderText="My PlaceholderText" Height="100" Width="500"
         HorizontalAlignment="Center" 
         BorderBrush="{ThemeResource MyBorderBrushMandatory}"
         VerticalAlignment="Center" ></TextBox>

另外,如果你想在主题改变时使用绑定来改变TextBoxBorderBrush,你应该让IsError属性实现INotifyPropertyChanged,同时你应该订阅@987654321 @ 事件更改 IsError 属性的值以从您的 BorderBrushColorConverter 获取 SolidColorBrush 的值,然后更新 UI。

以下是依赖于您上述代码的示例:

MainPage.xaml:

<Page.Resources>
    <local:BorderBrushColorConverter x:Key="BorderBrushColorConverter"/>
</Page.Resources>

<StackPanel>
    <TextBox PlaceholderText="My PlaceholderText" Height="100" Width="500" HorizontalAlignment="Center" 
             BorderBrush="{Binding IsError, Converter={StaticResource BorderBrushColorConverter}}"
             VerticalAlignment="Center" ></TextBox>
    <Button Content="Change Theme" Click="Button_Click"></Button>
</StackPanel>

MainPage.xaml.cs:

public sealed partial class MainPage : Page,INotifyPropertyChanged
{
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = this;
        this.ActualThemeChanged += MainPage_ActualThemeChanged;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void MainPage_ActualThemeChanged(FrameworkElement sender, object args)
    {
        IsError = !IsError;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.RequestedTheme = this.RequestedTheme == ElementTheme.Light ? ElementTheme.Dark : ElementTheme.Light;
    }

    private void OnPropertyChanged(string Name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(Name));
        }
    }

    private bool? isError=true;
    public bool? IsError
    {
        get
        {
            return isError;
        }
        set
        {
            isError = value;
            OnPropertyChanged("IsError");
        }
    }

}

---更新---

让我们谈谈您的样品。 首先,我们都知道您通过从 App.xaml 获取应用程序资源来设置 TextBoxBorderBrush。在您的 Page2.xaml.cs 中,您使用以下代码,

this.RequestedTheme = App.SelectedTheme;

这段代码只设置了UIElement(及其子元素)用于资源确定的UI主题,也就是说,该代码只设置了页面的主题,而没有设置Application。您的应用默认使用用户在 Windows 设置中设置的主题运行(设置 > 个性化 > 颜色 > 选择您的默认应用模式),您还可以设置应用的 RequestedTheme 属性以覆盖用户默认并指定哪个主题是用过。

作为 Remarks 部分:

主题只能在应用启动时设置,不能在运行时设置。在应用程序运行时尝试设置 RequestedTheme 会引发异常(Microsoft .NET 代码的 NotSupportedException)。如果您为用户提供选择作为应用 UI 一部分的主题的选项,则必须将设置保存在应用数据中并在应用重新启动时应用。

所以当你更改页面的RequestedTheme时,这不会影响Application的RequestedTheme,它仍然是你在示例的App.xaml中设置的Application的RequestedTheme,作为代码,

RequestedTheme="Light"

所以当您使用代码Application.Current.Resources 获取应用程序资源时,它仍然会获取“Light”主题资源。这与您使用ThemeResource 不同。对于您的这个问题,主题资源不是您想要的,您应该在资源中设置一些不同的颜色画笔,然后使用StaticResource根据您页面的资源设置获取不同的颜色画笔资源。

---更新2---

这里是一个简单的解决方案,只需在App.xaml中添加Application资源,

<Application.Resources>
        <Color x:Key="MyBorder">#6b6b6b</Color>
        <SolidColorBrush x:Key="MyBorderBrush" Color="{StaticResource MyBorder}" />

        <Color x:Key="MyBorderMandatory">#ff0000</Color>
        <SolidColorBrush x:Key="MyBorderBrushMandatory" Color="{StaticResource MyBorderMandatory}" />

        <Color x:Key="MyBorderDark">#c85332</Color>
        <SolidColorBrush x:Key="MyBorderBrushDark" Color="{StaticResource MyBorderDark}" />

        <Color x:Key="MyBorderMandatoryDark">#FFD700</Color>
        <SolidColorBrush x:Key="MyBorderBrushMandatoryDark" Color="{StaticResource MyBorderMandatoryDark}" />
...
</Application.Resources>

在 BorderBrushColorConverter.cs 中,更改 Convert 方法,

public object Convert(object value, Type targetType, object parameter, string language)
{
    var isError = value as bool? ?? false;
    if (isError)
    {
        if (App.SelectedTheme == ElementTheme.Light)
        {
            return Application.Current.Resources["MyBorderBrushMandatory"] as SolidColorBrush;
        }
        else
        {
            return Application.Current.Resources["MyBorderBrushMandatoryDark"] as SolidColorBrush;
        }
    }
    else
    {
        return null;
    }
}

在Page2.xaml中,改为静态资源引用,

<TextBox PlaceholderText="My PlaceholderText" Height="100" Width="500"
         HorizontalAlignment="Center" Style="{StaticResource NoHighlightTextBoxStyle}"
         BorderBrush="{Binding IsError, Converter={StaticResource BorderBrushColorConverter}}" 
         VerticalAlignment="Center" ></TextBox>

【讨论】:

  • 谢谢。但这里有一些澄清 1> IsError 是一个基于其他数据而不是主题更改的属性 2> 此外,属性更改没有任何意义,因为主题更改是从另一个页面完成的(比如设置)并导航到这些页面没有使用适当的主题资源。我创建了一个示例来重现此问题,您可以从 here 下载它
  • 我已经用 Update 部分更新了我的答案。你可以检查一下。
  • 所以,基本上,当我们使用ThemeResource 时,它会在我们更新RequestedTheme 时改变颜色,但就我而言,我是从Application.Current.Resources["MyBorderBrush"] 更新它,它仍然会加载基于颜色的关于 App Startup 的主题,对吧?另外,如果您可以发布一些关于我可以做些什么来解决我的问题的代码 sn-p 会有所帮助
  • 是的,就是这样。我将update2部分添加为一个简单的解决方案,您可以尝试一下。
【解决方案2】:

您正在运行时进行动态主题更改。所以将 StaticResource 更改为 ThemeResource。就是这样。

来自

BorderBrush="{StaticResource MyBorderBrush}"

BorderBrush="{ThemeResource MyBorderBrush}"

谢谢。

【讨论】:

  • 谢谢,请看我更新的帖子。我会创建新的 SO 线程,但考虑更新它,因为它更相关,而不是创建另一个线程。
猜你喜欢
  • 2017-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 1970-01-01
  • 2019-12-23
  • 2010-12-27
相关资源
最近更新 更多