Локализуйте изображения в WPF - PullRequest
1 голос
/ 21 августа 2010

Я создаю программу в 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 связан с тем, что мне нужны «два dacactextex» для моих изображений и текстов (которые приходят из файла XML) в моей реальной программе.

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 Ответ

1 голос
/ 21 августа 2010

Во-первых, вы должны прекратить использовать «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");
        }
    }

должно быть свойством зависимости, а не свойством clr, поддерживаемым INotify ...

EDIT

Я до сих пор не понимаю, как будет работать свойство 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, чтобы получить локализованный путь. А поскольку вы связываетесь со свойством LanguageCode в текстовом тексте данных при каждом его изменении, все изображения будут автоматически обновляться. Обратите внимание, что параметр конвертера не может быть привязан. Если вы хотите связать как filePath, так и код языка, используйте мультисвязывание.

* В коде могут быть синтаксические ошибки, я только пытаюсь передать концепцию

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...