App Culture 上的 WinRT XAML AppBarButton UI 样式问题已更改
WinRT XAML AppBarButton UI style issue on App Culture changed
我有两个自定义应用栏按钮,如下面的屏幕截图所示。这些按钮的样式写在 App.xaml 页面中。 app/device 语言更改后,按钮样式会变形。在比较和分析我之前准备的不同构建时,我发现在我在 App.xaml
中引入以下语言文化覆盖更改之前,这些样式工作得很好
CultureInfo ci = new CultureInfo(currentAppLanguage);
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = ci.Name;
CultureInfo.DefaultThreadCurrentCulture = ci;
CultureInfo.DefaultThreadCurrentUICulture = ci;
其中currentAppLanguage的值为App/Device对应的语言
此区域性更新很重要,因为一些控件(如 Datepicker 等)依赖此区域性更改来根据所选语言进行翻译。
错误:
正确:
该页面在英语文化下运行良好。但是当用户通过应用程序或 Phone 更新语言时,按钮样式会中断。
我在应用加载时根据所选语言覆盖主要语言区域性。文化变革是否可能影响 XAML 样式和元素?
任何建议都会有很大帮助。
提前致谢。
下面是应用栏按钮控件和样式
Button:
<AppBarButton
Visibility="{Binding CanReject, Converter={StaticResource BoolToVisibilityConverter}}"
x:Name="abReject"
Grid.Column="3"
Height="62"
Width="62"
Style="{StaticResource RejectAppBarButtonStyle}"
IsEnabled="{Binding LoadedApproval.ApprovalState, Converter={StaticResource StringComparerToBoolConverter}, ConverterParameter=Pending}"
BorderBrush="{StaticResource DictationGray}"
BorderThickness="2"
Foreground="White"
Background="{StaticResource ApprovalRejectRed}"
Margin="0,0">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Click">
<Core:GoToStateAction StateName="Rejecting" UseTransitions="True"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</AppBarButton>
Style:
<Style x:Key="RejectAppBarButtonStyle" TargetType="AppBarButton">
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="AppBarButton" >
<Grid x:Name="RootGrid" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullSize"/>
<VisualState x:Name="Compact">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="TextLabel">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="RootGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="60"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<RepositionThemeAnimation TargetName="RootGrid"/>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PointOverOverlay"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<PointerDownThemeAnimation TargetName="RootGrid"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="OuterEllipse">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApprovalRejectRed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To="0.5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="RootGrid"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="PointerFocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse
x:Name="OuterEllipse"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}"
Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="2"
UseLayoutRounding="True">
</Ellipse>
<Grid>
<Ellipse
x:Name="BackgroundEllipse"
Height="{Binding Height, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Width="{Binding Width, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Fill="{TemplateBinding Background}"
UseLayoutRounding="True">
</Ellipse>
<Ellipse
x:Name="PointOverOverlay"
Opacity="0"
Height="{Binding Height, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Width="{Binding Width, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Fill="{StaticResource PointOverShade}"
UseLayoutRounding="True">
</Ellipse>
<Path
x:Name="Content"
Data="M1.5,1.5 L40.392,40.391 M1.5,40.391 L40.392,1.5"
VerticalAlignment="Center"
HorizontalAlignment="Center"
StrokeStartLineCap="Round"
Stretch="Uniform"
StrokeEndLineCap="Round"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="3"
StrokeLineJoin="Round"
Height="{Binding Height, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.33, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Width="{Binding Width, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.33, RelativeSource={RelativeSource Mode=TemplatedParent}}">
</Path>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我找到了问题发生的地方。那是在转换器 class ArithmeticOperationConverter 中。下面是转换方法。
public object Convert(object value, Type targetType, object parameter, string language)
{
if (parameter == null)
return value;
Double val;
Double param;
if (Double.TryParse(value.ToString(), out val) && Double.TryParse(parameter.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out param))
{
switch (Mode)
{
case (ArithmeticMode.Addition):
return val + param;
case (ArithmeticMode.Subtratction):
return val - param;
case (ArithmeticMode.Multiplication):
return val * param;
case (ArithmeticMode.Division):
return val / param;
default:
return val;
}
}
else
return value;
}
这里是 TryParse() 方法,它在条件导致问题的情况下解析参数值。传递的参数字符串值(例如)是“0.78”,结果是 78.0 而不是 0.78,导致 UI 中的失真。 发生这种情况是因为数字符号之间的文化差异。我向 TryParse() 方法添加了 CultureInfo.InvariantCulture 参数,它解决了问题。
谢谢你的建议@GraceFeng-MSFT
我有两个自定义应用栏按钮,如下面的屏幕截图所示。这些按钮的样式写在 App.xaml 页面中。 app/device 语言更改后,按钮样式会变形。在比较和分析我之前准备的不同构建时,我发现在我在 App.xaml
中引入以下语言文化覆盖更改之前,这些样式工作得很好CultureInfo ci = new CultureInfo(currentAppLanguage);
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = ci.Name;
CultureInfo.DefaultThreadCurrentCulture = ci;
CultureInfo.DefaultThreadCurrentUICulture = ci;
其中currentAppLanguage的值为App/Device对应的语言
此区域性更新很重要,因为一些控件(如 Datepicker 等)依赖此区域性更改来根据所选语言进行翻译。
错误:
正确:
该页面在英语文化下运行良好。但是当用户通过应用程序或 Phone 更新语言时,按钮样式会中断。
我在应用加载时根据所选语言覆盖主要语言区域性。文化变革是否可能影响 XAML 样式和元素?
任何建议都会有很大帮助。 提前致谢。
下面是应用栏按钮控件和样式
Button:
<AppBarButton
Visibility="{Binding CanReject, Converter={StaticResource BoolToVisibilityConverter}}"
x:Name="abReject"
Grid.Column="3"
Height="62"
Width="62"
Style="{StaticResource RejectAppBarButtonStyle}"
IsEnabled="{Binding LoadedApproval.ApprovalState, Converter={StaticResource StringComparerToBoolConverter}, ConverterParameter=Pending}"
BorderBrush="{StaticResource DictationGray}"
BorderThickness="2"
Foreground="White"
Background="{StaticResource ApprovalRejectRed}"
Margin="0,0">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Click">
<Core:GoToStateAction StateName="Rejecting" UseTransitions="True"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</AppBarButton>
Style:
<Style x:Key="RejectAppBarButtonStyle" TargetType="AppBarButton">
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="AppBarButton" >
<Grid x:Name="RootGrid" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullSize"/>
<VisualState x:Name="Compact">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="TextLabel">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="RootGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="60"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<RepositionThemeAnimation TargetName="RootGrid"/>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PointOverOverlay"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<PointerDownThemeAnimation TargetName="RootGrid"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="OuterEllipse">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApprovalRejectRed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To="0.5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="RootGrid"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="PointerFocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse
x:Name="OuterEllipse"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}"
Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="2"
UseLayoutRounding="True">
</Ellipse>
<Grid>
<Ellipse
x:Name="BackgroundEllipse"
Height="{Binding Height, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Width="{Binding Width, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Fill="{TemplateBinding Background}"
UseLayoutRounding="True">
</Ellipse>
<Ellipse
x:Name="PointOverOverlay"
Opacity="0"
Height="{Binding Height, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Width="{Binding Width, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.78, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Fill="{StaticResource PointOverShade}"
UseLayoutRounding="True">
</Ellipse>
<Path
x:Name="Content"
Data="M1.5,1.5 L40.392,40.391 M1.5,40.391 L40.392,1.5"
VerticalAlignment="Center"
HorizontalAlignment="Center"
StrokeStartLineCap="Round"
Stretch="Uniform"
StrokeEndLineCap="Round"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="3"
StrokeLineJoin="Round"
Height="{Binding Height, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.33, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Width="{Binding Width, Converter={StaticResource ArithmeticOperationConverter}, ConverterParameter=0.33, RelativeSource={RelativeSource Mode=TemplatedParent}}">
</Path>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我找到了问题发生的地方。那是在转换器 class ArithmeticOperationConverter 中。下面是转换方法。
public object Convert(object value, Type targetType, object parameter, string language)
{
if (parameter == null)
return value;
Double val;
Double param;
if (Double.TryParse(value.ToString(), out val) && Double.TryParse(parameter.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out param))
{
switch (Mode)
{
case (ArithmeticMode.Addition):
return val + param;
case (ArithmeticMode.Subtratction):
return val - param;
case (ArithmeticMode.Multiplication):
return val * param;
case (ArithmeticMode.Division):
return val / param;
default:
return val;
}
}
else
return value;
}
这里是 TryParse() 方法,它在条件导致问题的情况下解析参数值。传递的参数字符串值(例如)是“0.78”,结果是 78.0 而不是 0.78,导致 UI 中的失真。 发生这种情况是因为数字符号之间的文化差异。我向 TryParse() 方法添加了 CultureInfo.InvariantCulture 参数,它解决了问题。
谢谢你的建议@GraceFeng-MSFT