在WPF中本地化图像

时间:2010-08-20 22:30:54

标签: c# .net wpf xaml localization

我正在WPF中构建一个程序,该程序必须具有多语言支持,并且能够在运行时切换语言。我的问题涉及本地化的图像部分。

我已经构建了一个解决方案,它不能按照我希望的方式工作,我想帮助解决这些问题。下面发布的代码只是我想要实现的概念的演示。我真正的程序有很多图片,所以我想避免将它们全部放在一个列表中,逐个更新。

我的想法是根据他们所属的语言命名图像。 OriginalSource属性(缺少更好的名称)格式为“Koala。(lang).jpg”,英语和法语的两个图像称为“Koala.en-GB.jpg”和“Koala.fr-FR” .JPG”。

我的问题是,如果没有在(1)注释的代码,图像将不会被分配一个“真正的”源(在Image类中)。

此外,在使用了(1)处的代码(违反了我不希望使用所有图像的枚举)之后,在按钮上单击时,(2)处的“真实”源不会更新。我希望(3)和(4)可以解决这些问题,但显然他们没有。

非常感谢帮助。 代码如下:

MainWindow.xaml(不正确)

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="700" Width="525">
    <Window.Resources>
        <local:LanguageCodeSetter x:Key="CodeSetter" LanguageCodeValue="en-GB" />
    </Window.Resources>

    <StackPanel>
        <local:LocalizedImage x:Name="imgKoala" LanguageCode="{Binding Source={StaticResource CodeSetter}, Path=LanguageCodeValue, Mode=OneWay}" OriginalSource="Koala.(lang).jpg" Height="300" Stretch="Uniform" />
        <local:LocalizedImage x:Name="imgPenguins" LanguageCode="{Binding Source={StaticResource CodeSetter}, Path=LanguageCodeValue, Mode=OneWay}" OriginalSource="Penguins.(lang).jpg" Height="300" Stretch="Uniform" />
        <Button Content="Don't click here!" Click="Button_Click" />
    </StackPanel>
</Window>

MainWindow.xaml.cs(不正确)

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        private string LanguageCodeResource
        {
            get
            {
                return ((LanguageCodeSetter)Resources["CodeSetter"]).LanguageCodeValue;
            }
            set
            {
                ((LanguageCodeSetter)Resources["CodeSetter"]).LanguageCodeValue = value;
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            //(1)
            //imgKoala.OriginalSource = imgKoala.OriginalSource;
            //imgPenguins.OriginalSource = imgPenguins.OriginalSource;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            LanguageCodeResource = "fr-FR";

            //(2)
            //imgKoala.LanguageCode = imgKoala.LanguageCode;
            //imgPenguins.LanguageCode = imgPenguins.LanguageCode;
        }
    }

    public class LocalizedImage : Image
    {
        public static readonly DependencyProperty LanguageCodeProperty = DependencyProperty.Register("LanguageCode", typeof(string), typeof(LocalizedImage));
        public static readonly DependencyProperty OriginalSourceProperty = DependencyProperty.Register("OriginalSource", typeof(string), typeof(LocalizedImage));

        public string LanguageCode
        {
            get
            {
                return (string)GetValue(LanguageCodeProperty);
            }
            set
            {
                SetValue(LanguageCodeProperty, value);
                //(3)
                SetValue(SourceProperty, new BitmapImage(new Uri(OriginalSource.Replace("(lang)", value), UriKind.RelativeOrAbsolute)));
            }
        }

        public string OriginalSource
        {
            get
            {
                return (string)GetValue(OriginalSourceProperty);
            }
            set
            {
                SetValue(OriginalSourceProperty, value);
                //(4)
                SetValue(SourceProperty, new BitmapImage(new Uri(value.Replace("(lang)", LanguageCode), UriKind.RelativeOrAbsolute)));
            }
        }
    }

    public class LanguageCodeSetter : INotifyPropertyChanged
    {
        private string _languageCode;

        public event PropertyChangedEventHandler PropertyChanged;

        public string LanguageCodeValue
        {
            get
            {
                return _languageCode;
            }
            set
            {
                _languageCode = value;
                NotifyPropertyChanged("LanguageCodeValue");
            }
        }

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

@NVM

  • 关于名字混乱的观点。我已经更新了我的代码。
  • 我使用INotifyPropertyChanged对象的原因是我希望一个变量(即名为CodeSetter的资源)中的更改传播到LocalizedImage的所有实例。这样做的原因是我正在构建一个包含大量图像的WPF应用程序,并且我不希望被强制将它们全部添加到代码隐藏的列表中(因此忘记添加一些图像,并创造未来重构应用程序更繁琐)。单击该按钮,“LanguageCode”的值在LocalizedImage的所有实例中都会发生变化,因此传播部分似乎有效。但是,在(3)处设置“真实”源不会。我也尝试将base.Source设置为相同的值(新的BitmapImage(...)),但结果相同。
  • 属性(LanguageCodeResource)仅用于Button_Click事件处理程序。

也许我的目标是错误的方向来解决这个问题?我们非常感谢其他反馈。

@NVM 这就是诀窍。非常感谢你!

对于任何有兴趣的人,我附上我的正确代码。有些繁琐的DataContext数据类型是因为我的实际程序中的图像和文本(来自XML文件)需要“两个datacontexts”。

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication2"
    Title="MainWindow" Height="700" Width="525">
<Window.Resources>
    <local:LocalizedImageSourceConverter x:Key="localizedImageSourceConverter" />
</Window.Resources>
<StackPanel x:Name="layoutRoot">
    <Image x:Name="imgKoala" Source="{Binding Path=LanguageCode, Converter={StaticResource localizedImageSourceConverter}, ConverterParameter='Koala.(lang).jpg'}" Height="300" Stretch="Uniform" />
    <Image x:Name="imgPenguins" Source="{Binding Path=LanguageCode, Converter={StaticResource localizedImageSourceConverter}, ConverterParameter='Penguins.(lang).jpg'}" Height="300" Stretch="Uniform" />
    <Button Content="Don't click here!" Click="Button_Click" />
</StackPanel>

MainWindow.cs.xaml

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        private string LanguageCodeValue
        {
            set
            {
                layoutRoot.DataContext = new
                {
                    LanguageCode = value
                };
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            LanguageCodeValue = "en-GB";
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            LanguageCodeValue = "fr-FR";
        }
    }

    public class LocalizedImageSourceConverter : IValueConverter
    {
        public object Convert(object values, Type targetType, object parameter, CultureInfo culture)
        {
            return ((string)parameter).Replace("(lang)", (string)values);
        }

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

1 个答案:

答案 0 :(得分:1)

首先,您应该停止使用'LanguageCode'来命名几乎所有内容。 真的令人困惑:D

其次是

    <Window.Resources>
    <local:LanguageCodeSetter x:Key="LanguageCode" LanguageCode="en-GB" />
</Window.Resources>

有任何意义

        public string LanguageCode
    {
        get
        {
            return _languageCode;
        }
        set
        {
            _languageCode = value;
            NotifyPropertyChanged("LanguageCode");
        }
    }

应该是依赖属性,而不是由INotify支持的clr属性...

修改

我仍然不知道LanguageCode属性如何在资源部分工作。

无论如何已经理解了你想要实现的目标,有一个非常简单的解决方案

<Image Source="{Binding Path=LanguageCode, Converter={StaticResource localizedImageSourceConverter}, ConverterParameter='Koala.jpg'}"/>

public class LocalizedImageSourceConverter : IValueConverter
{
    public object Convert(object values, Type targetType, object parameter, CultureInfo culture)
    {
        string fileName = Path.GetFileNameWithoutExtension((string)parameter);
        string extension = Path.GetExtension((string)parameter);
        string languageCode = (string)values;

        return string.Format("{0}{1}{2}", fileName, languageCode, extension);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

我没有将Source属性绑定到filePath(URI),而是将它绑定到LanguageCode属性。 LanguageCode属性应该在您的ViewModel或您绑定的任何datacontext对象中。

转换器将基本图像的路径作为参数,并将其与绑定的LanguageCodeProperty组合,为您提供本地化路径。而且,由于您在datacontext中绑定了LanguageCode属性,因此无论何时更改,所有图像都将自动更新。请注意,转换器参数不能绑定。如果要绑定filePath和语言代码,请使用多绑定。

*代码中可能存在语法错误,我只想传达概念