четверг, 30 мая 2013 г.

Локализованный BooleanToStringConverter.

Для разработчиков пользовательских интерфейсов актуальна задача отображения значения типа Boolean в виде локализованной строки. Т.е. вместо "True" и "False" требуется отобразить "Да" и "Нет" (естественно в зависимости от языка ОС). В связи с этим, хочу предложить интересное решение.
Для начала следует определиться, откуда получить локализованное значение типа Boolean в человеческом виде? Для этого используем библиотеку "User32.dll", которая и вернет нам эти данные.


Как видно на скриншоте, под идентификаторами 805 и 806 имеются строки "&Да" и "&Нет" соответственно. Вот их и будем использовать.
Чтобы долго не описывать сам процесс, приведу код самого конвертера с подробными комментариями:

BooleanToStringConverter.cs:
using System;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Data;

namespace WpfCsharp.Converters
{
    /// <summary>
    /// This class converts a Boolean value to a localized String.
    /// </summary>
    [ValueConversion(typeof(Boolean), typeof(String))]
    public sealed class BooleanToStringConverter : IValueConverter
    {
        #region Ctor

        /// <summary>
        /// Initializes a new instance of the <see cref="BooleanToStringConverter"/> class.
        /// </summary>
        static BooleanToStringConverter()
        {
            var stringBuilder = new StringBuilder(256);
            var user32 = LoadLibrary(Path.Combine(Environment.SystemDirectory, "User32.dll"));
            LoadString(user32, 805, stringBuilder, stringBuilder.Capacity);
            Yes = stringBuilder.ToString().Replace("&", "");
            LoadString(user32, 806, stringBuilder, stringBuilder.Capacity);
            No = stringBuilder.ToString().Replace("&", "");
        }

        #endregion

        #region Static Members

        /// <summary>
        /// Loads a string resource from the executable file associated with a specified module,
        /// copies the string into a buffer, and appends a terminating null character.
        /// </summary>
        /// <param name="hInstance">A handle to an instance of the module whose executable file contains the string resource.</param>
        /// <param name="uID">The identifier of the string to be loaded.</param>
        /// <param name="lpBuffer">The buffer is to receive the string.</param>
        /// <param name="nBufferMax">The size of the buffer, in characters.</param>
        /// <returns>
        /// If the function succeeds, the return value is the number of characters copied into the buffer, 
        /// not including the terminating null character, or zero if the string resource does not exist.
        /// </returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax);

        /// <summary>
        /// Loads the specified module into the address space of the calling process.
        /// </summary>
        /// <param name="lpFileName">The name of the module.</param>
        /// <returns>If the function succeeds, the return value is a handle to the module.</returns>
        [DllImport("kernel32")]
        static extern IntPtr LoadLibrary(string lpFileName);

        /// <summary>
        /// Returns a localized string Yes.
        /// </summary>
        public static string Yes { get; private set; }

        /// <summary>
        /// Returns a localized string No.
        /// </summary>
        public static string No { get; private set; }

        #endregion

        #region IValueConverter Members

        /// <summary>
        /// Modifies the source data before passing it to the target for display in the UI.
        /// </summary>
        /// <param name="value">The source data being passed to the target.</param>
        /// <param name="targetType">The Type of data expected by the target dependency property.</param>
        /// <param name="parameter">An optional parameter to be used in the converter logic.</param>
        /// <param name="culture">The culture of the conversion.</param>
        /// <returns>The value to be passed to the target dependency property.</returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Yes : No;
        }

        /// <summary>
        /// Modifies the target data before passing it to the source object. This method is called only in TwoWay bindings.
        /// </summary>
        /// <param name="value">The target data being passed to the source.</param>
        /// <param name="targetType">The Type of data expected by the source object.</param>
        /// <param name="parameter">An optional parameter to be used in the converter logic.</param>
        /// <param name="culture">The culture of the conversion.</param>
        /// <returns>The value to be passed to the source object.</returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

Реализацию "ConvertBack" оставил на ваше усмотрение.
Как теперь его использовать, приведу ниже:

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:wpfcsharp="clr-namespace:WpfCsharp.Converters"
        Title="MainWindow" Height="350" Width="525">
    
    <Window.Resources>
        <wpfcsharp:BooleanToStringConverter x:Key="booleanToStringConverter"/>
    </Window.Resources>
    
    <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
        <CheckBox Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={StaticResource booleanToStringConverter}}"/>
        <CheckBox Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={StaticResource booleanToStringConverter}}"/>
    </StackPanel>
    
</Window>

В результате мы получим локализованное значение типа Boolean в читаемом виде:





Комментариев нет:

Отправить комментарий