Невозможно использовать IMultiValueConverter в WPF для разрешения метрического или имперского ввода - PullRequest
4 голосов
/ 03 июля 2010

Я хотел бы создать форму CF WPF, которая собирает измерения оборудования, но некоторые пользователи предпочитают использовать измерения в футах и ​​дюймах, в то время как другие (младшие) пользователи делают все в метрике.База данных хранит все в метрах, и я решил, что это идеальное место для использования IMultiValueConverter .

Каждая форма имеет DependencyProperty с именем UseImperialMeasurements в котором хранятся пользовательские настройки, и я передаю это значение в функцию Convert вместе с фактическим измерением в метрах.Код до сих пор выглядит следующим образом:

<Label>Length:</Label>
<TextBox>
    <TextBox.Text>
        <MultiBinding Converter="{StaticResource DistanceStringConverter}" Mode="TwoWay">
            <Binding Path="Length" />
            <Binding ElementName="ThisControl" Path="UseImperialMeasurements" />
        </MultiBinding>
    </TextBox.Text>
</TextBox>


public class DistanceStringConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values.Length != 2 || !(values[0] is Double) || !(values[1] is Boolean)) return "ERROR";

        Double measurement = (Double)values[0];   // Always in meters
        Boolean useImperial = (Boolean)values[1];
        string unit;

        if (useImperial == true)
        {
            double feet, inches;

            inches = (measurement * 100) / 2.54;

            feet = Math.Floor(inches / 12);
            inches = inches % 12;

            var replacements = new object[4];

            replacements[0] = feet.ToString("#,0");
            replacements[1] = "'";
            replacements[2] = inches.ToString("0");
            replacements[3] = "\"";

            // Display like 12'4"
            return string.Format("{0}{1}{2}{3}", replacements);
        }
        else
        {
            // Display like 5,987.97m
            return string.Format("{0}{1}", measurement.ToString("#,0.##"), m);                
        }
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        // ToDo: Figure out if imperial or metric measurements are prefered...
    }
}

Это хорошо работает для отображения измерений, но брать их в качестве входных данных в метрических или британских единицах было проблематично, поскольку я не могу увидеть связанное значение UseImperialMeasurements свойство в методе ConvertBack .Поэтому я не только не могу угадать, вводит ли пользователь футы или метры, когда не указаны единицы измерения, но у меня нет возможности узнать, какое логическое значение нужно вернуть, чтобы пользовательское предпочтение не изменилось.

Можно ли передать значение UseImperialMeasurements в функцию ConvertBack ?

Ответы [ 2 ]

1 голос
/ 03 июля 2010

Ваш метод ConvertBack должен проанализировать единицы из строки, а установить свойство UseImperialMeasurements (с помощью элемента секунд в возвращенном массиве).

0 голосов
/ 10 июля 2010

Сохраните значение UseImperialMeasurements в качестве настройки приложения (или в любом другом месте, которое вам действительно нужно, но вариант использования предпочитает настройку пользователя в рамках приложения). Для этого дважды щелкните элемент «Свойства» в дереве проекта в Visual Studio. Там просто перейдите на вкладку «Настройки» и добавьте «UseImperialMeasurements» в качестве bool, область действия User и установите значение по умолчанию.

Затем, где бы вы ни находились в своем коде, откройте и измените значение с помощью свойства Properties.Settings.Default.UseImperialMeasurements.

Если вы не забудете вызвать Properties.Settings.Default.Save () перед закрытием формы или приложения, настройка будет «Придерживаться».

В XAML вы получите доступ к настройке с помощью этой привязки:

{Binding Source={x:Static my:Settings.Default},Path=UseImperialMeasurements}

Или забудьте о конвертерах. Запеките эту функциональность в ViewModel и сохраните значение UseImperialMeasurements в качестве настройки приложения (или в любом другом месте, где вы действительно хотите, но вариант использования предпочтителен настройкой пользователя)

public class BackingDataClass
{
    public double LengthAlwaysMetric { get; set; }
}
public class BackingDataClassViewModel : INotifyPropertyChanged
{
    public BackingDataClass Data { get; set; }
    public double Length
    {
        get
        {
            if (Properties.Settings.Default.UseImperialMeasurements == true)
            {
                return ConvertToImperial(Data.LengthAlwaysMetric);
            }
            else
            {
                return _lengthAlwaysMetric;
            }
        }
        set
        {
            if (Properties.Settings.Default.UseImperialMeasurements == true)
            {
                Data.LengthAlwaysMetric = ConvertToMetric(value);
            }
            else
            {
                Data.LengthAlwaysMetric = value;
            }
            PropertyChanged(this, new PropertyChangedEventArgs("Length"));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...