我觉得@BionicCode已经给出了相当全面的答案,但我想再补充一点。
我认为最符合您要求的最佳解决方案是样式触发器。
我看到Bionic已经包括了这个,但这里有一个MCVE:
<Window x:Class="project-name.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="120" Width="300">
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="15,15,0,0">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Language: " VerticalAlignment="Center"/>
<ComboBox x:Name="LanguageCB" HorizontalAlignment="Left" SelectedIndex="0">
<ComboBoxItem Content="None ?"/>
<ComboBoxItem Content="English"/>
</ComboBox>
</StackPanel>
<Border Margin="0,10,0,0" BorderThickness="1" BorderBrush="Black" Padding="2">
<TextBlock Text="Becomes visible when "LanguageCB" changes selection">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=LanguageCB, Path=SelectedIndex}" Value="1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
</StackPanel>
</Window>
然而... 如果你真的在应用程序中进行本地化,而不仅仅是使用这个作为例子,那么我认为有更好的解决方案。
首先花几分钟阅读关于WPF全球化和本地化的内容。
然后在项目属性中添加至少一个语言资源文件(例如'Resources.ja-JP.resx'),并不要忘记将你的Resources.resx文件标记为public。在这些.resx文件中放置一些本地化字符串。
然后将你的TextBlock的文本绑定到该属性:
<TextBlock Text="{Binding Path=ResourceName, Source={StaticResource Resources}}"/>
接下来,您需要一些代码来处理切换文化的问题。这里有很多选项,但我会包含一些我过去使用过的代码。
CultureResources.cs
namespace Multi_Language_Base_App.Cultures
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Diagnostics;
using System.Windows.Data;
public class CultureResources
{
private static ObjectDataProvider provider;
public static event EventHandler<EventArgs> CultureUpdateEvent;
private static bool bFoundInstalledCultures = false;
private static List<CultureInfo> pSupportedCultures = new List<CultureInfo>();
public static List<CultureInfo> SupportedCultures
{
get { return pSupportedCultures; }
}
public CultureResources()
{
if (!bFoundInstalledCultures)
{
Debug.WriteLine("Get Installed cultures:");
CultureInfo tCulture = new CultureInfo("");
foreach (string dir in Directory.GetDirectories(AppDomain.CurrentDomain.BaseDirectory))
{
try
{
DirectoryInfo dirinfo = new DirectoryInfo(dir);
tCulture = CultureInfo.GetCultureInfo(dirinfo.Name);
string exe = System.Reflection.Assembly.GetExecutingAssembly().Location;
if (dirinfo.GetFiles(Path.GetFileNameWithoutExtension(exe) + ".resources.dll").Length > 0)
{
pSupportedCultures.Add(tCulture);
Debug.WriteLine(string.Format(" Found Culture: {0} [{1}]", tCulture.DisplayName, tCulture.Name));
}
}
catch (ArgumentException)
{
}
}
bFoundInstalledCultures = true;
}
}
public Properties.Resources GetResourceInstance()
{
return new Properties.Resources();
}
public static ObjectDataProvider ResourceProvider
{
get
{
if (provider == null)
provider = (ObjectDataProvider)App.Current.FindResource("Resources");
return provider;
}
}
public static void ChangeCulture(CultureInfo culture)
{
if (pSupportedCultures.Contains(culture))
{
Properties.Resources.Culture = culture;
ResourceProvider.Refresh();
RaiseCultureUpdateEvent(null, new EventArgs());
Debug.WriteLine(string.Format("Culture changed to [{0}].", culture.NativeName));
}
else
{
Debug.WriteLine(string.Format("Culture [{0}] not available", culture));
}
}
private static void RaiseCultureUpdateEvent(object sender, EventArgs e)
{
EventHandler<EventArgs> handleit = CultureUpdateEvent;
CultureUpdateEvent?.Invoke(sender, e);
}
}
}
最后一个问题应该是如何从xaml提供对文化资源的访问方式。这可以使用ObjectDataProvider来完成。
您可以直接将其放在App.xaml中或放在单独的文件中,并在App.xaml中引用它。
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Cultures="clr-namespace:Multi_Language_Base_App.Cultures">
<!-- Contains the current instance of the ProjectName.Properties.Resources class.
Used in bindings to get localized strings and automatic updates when the culture is updated -->
<ObjectDataProvider x:Key="Resources"
ObjectType="{x:Type Cultures:CultureResources}"
MethodName="GetResourceInstance"/>
<!-- Provides access to list of currently available cultures -->
<ObjectDataProvider x:Key="CultureResourcesDS"
ObjectType="{x:Type Cultures:CultureResources}"/>
</ResourceDictionary>
当您这样做时,您的字符串绑定可以自动匹配系统文化(否则将成为通用资源中的默认值)。此外,用户可以随时切换文化。
在您的示例中,ComboBox SelectionChanged事件将被用作更改文化的起点,如下所示:
CultureInfo CultureJapanese = new CultureInfo("ja-JP");
Cultures.CultureResources.ChangeCulture(CultureJapanese);
我更喜欢使用命令来完成这个任务,但这取决于你。
DataTriggers
的Style
也是可重用和易读的。您可以使用Style.BasedOn
属性轻松扩展(“继承”)样式。如果您需要处理多个条件,则MultiDataTrigger
(或MultiTrigger
)也是一个好的灵活解决方案。当然,在特殊情况下,IValueConverter
更加强大,例如,如果您需要访问模板或使用反射。 - BionicCode