我正在为我的大学期末项目(论文)开发一个 WPF 应用程序。目标之一是能够动态更改 UI 的语言。我认为按照我尝试的方式做这件事并不是一个好主意,因为它需要大量代码,但为了学习,我会坚持下去。这个想法是将 XAML 中的文本属性绑定到 LanguageViewModel 中的属性,当用户从下拉菜单中更改当前语言时,UI 中的所有字符串都应更改为所选语言。使用下面的代码,OnPropertyChanged 方法被执行,但 UI 元素没有更新,经过大量调试后,我仍然不知道原因。
我目前正在尝试使用单个 TextBlock 控件。我已将其放在注释之间,以便于查找。
这是我的 MainWindow.xaml
<Window x:Class="AdjustrixWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AdjustrixWPF"
xmlns:userControls="clr-namespace:AdjustrixWPF.View.UserControls"
mc:Ignorable="d"
Title="MainWindow" WindowState="Maximized" Height="650" Width="850" WindowStyle="None"
MouseLeftButtonDown="Window_MouseLeftButtonDown"
Background="{DynamicResource BackgroundBrush}">
<Grid Name="MainGrid"
Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="25*"/>
<RowDefinition Height="75*"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0" Width="{Binding ElementName=MainGrid, Path=ActualWidth}"
HorizontalAlignment="Left" Grid.RowSpan="2" Background="{DynamicResource BackgroundBrush}" Style="{StaticResource TabControlStyle}">
<TabItem Background="{DynamicResource BackgroundBrush}"
Style="{StaticResource TabItemStyle}">
<TabItem.Header>
<userControls:TabHeader DataContext="{Binding languageViewModel}"
Text="File"
IsMouseOver="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=TabItem}}"
IsSelected="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}"
Style="{StaticResource TabHeaderStyle}"
Height="20"/>
</TabItem.Header>
<StackPanel Orientation="Horizontal">
<Border BorderBrush="{DynamicResource ForegroundBrush}"
BorderThickness="0 0 1 0"
Margin="5">
<Grid Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=StackPanel}}"
Width="300"
x:Name="TabPanelGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="25*"/>
</Grid.ColumnDefinitions>
<Grid Height="{Binding ElementName=TabPanelGrid, Path=ActualHeight}">
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="45*"/>
<RowDefinition Height="45*"/>
</Grid.RowDefinitions>
<!-- =========================================================== -->
<!-- This is the control I am currently experimenting with-->
<TextBlock x:Name="AppearanceBlock"
Style="{StaticResource TextBlockTabPanel}"
Text="{Binding languageViewModel.Appearance, UpdateSourceTrigger=PropertyChanged}"
Margin="0 0 0 3"/>
<!-- =========================================================== -->
<userControls:LabeledComboBox LabelText="Language"
ComboBoxItemsSource="{Binding languageViewModel.Languages}"
ComboBoxSelectedItem="{Binding languageViewModel.CurrentLanguage, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1"
x:Name="LanguageBox"/>
<userControls:LabeledComboBox LabelText="Theme"
ComboBoxItemsSource="{Binding Path=themeViewModel.Themes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ComboBoxSelectedItem="{Binding Path=themeViewModel.SelectedTheme, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="2"
x:Name="ThemeBox"/>
</Grid>
</Grid>
</Border>
</StackPanel>
</TabItem>
<TabItem Style="{StaticResource TabItemStyle}">
<TabItem.Header>
<userControls:TabHeader Text="Data"
IsMouseOver="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=TabItem}}"
IsSelected="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}"
Style="{StaticResource TabHeaderStyle}"
Height="20"/>
</TabItem.Header>
<StackPanel>
</StackPanel>
</TabItem>
</TabControl>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="_" Style="{DynamicResource TitleBarButtonStyle}" Name="Minimize" Click="Minimize_Click"/>
<Button Content="🗖" Style="{DynamicResource TitleBarButtonStyle}" Name="Restore" Click="Restore_Click"/>
<Button Content="╳" Style="{DynamicResource TitleBarButtonStyle}" Name="Close" Click="Close_Click"/>
</StackPanel>
</Grid>
这是设置数据上下文的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
MainWindowViewModel mainWindowViewModel = new();
this.DataContext = mainWindowViewModel;
}
这是 MainWindowViewModel:
public class MainWindowViewModel : ViewModelBase
{
public ThemeViewModel themeViewModel { get; set; }
public LanguageViewModel languageViewModel { get; set; }
public MainWindowViewModel()
{
themeViewModel = new ThemeViewModel();
languageViewModel = new LanguageViewModel();
}
}
这是语言视图模型:
internal class StringEntry
{
public string Bulgarian { get; set; }
public string English { get; set; }
public StringEntry(string bg, string en)
{
Bulgarian = bg;
English = en;
}
public string GetString(Language currentLanguage)
{
if (currentLanguage == Language.English)
{
return English;
}
return Bulgarian;
}
}
public class LanguageViewModel : ViewModelBase
{
private StringEntry file = new("Файл", "File");
private StringEntry data = new("Данни", "Data");
private StringEntry appearance = new("Изглед", "Appearance");
private Language currentLanguage;
public LanguageViewModel()
{
File = file.GetString(currentLanguage);
Data = data.GetString(currentLanguage);
Appearance = appearance.GetString(currentLanguage);
//todo: later load it from AppData/Local
currentLanguage = Language.English;
}
public string CurrentLanguage
{
get
{
return currentLanguage.ToString();
}
set
{
currentLanguage = Language.English.ToString() == value ? Language.English : Language.Bulgarian;
File = Language.English == App.Language ? file.English : file.Bulgarian;
Data = data.GetString(currentLanguage);
Appearance = appearance.GetString(currentLanguage);
OnPropertyChanged();
OnPropertyChanged(nameof(File));
}
}
public string File
{
get { return file.GetString(currentLanguage); }
set
{
_ = value;
OnPropertyChanged();
}
}
public string Data
{
get { return data.GetString(currentLanguage); }
set
{
_ = value;
OnPropertyChanged();
}
}
public string Appearance
{
get { return appearance.GetString(currentLanguage); }
set { _ = value; OnPropertyChanged(); }
}
}
这是基础视图模型类:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string member = null)
{
PropertyChanged?.Invoke(member, new PropertyChangedEventArgs(member));
}
}
任何帮助都将不胜感激!