Конвертер WPF в GridViewColumn - сохраните значения для ConvertBack-Method и имеете собственный Binding-Instance для каждой строки

У меня есть GridView с некоторыми столбцами, отображающими материалы. Все значения модели представления сохраняются в кг, для некоторых представлений следует преобразовывать и отображать их в литрах. Что легко сделать одним способом, используя IMultiValueConverter.

public object Convert(object[] values, ...){
    var valueInKg = (double)values[0];
    var density = (double)values[1];

    return valueInKg/density;
}

Теперь у меня проблемы с обратным преобразованием. Я пытался сохранить входные значения (плотность) в конвертере, но у меня есть один экземпляр и, следовательно, иногда неправильные значения плотности. Я нашел этот подход x:shared="false", но хотите установить преобразователь в класс, производный от System.Windows.Data.MultiBinding.

public class MyBinding : MultiBinding {
    public MyBinding(){
        Converter = new MyConverter();
    }
}

Я предполагал, что это приведет к созданию отдельного экземпляра для каждой привязки, но это не так. Как я могу этого добиться?

РЕДАКТИРОВАТЬ: Как было предложено mm8 в этом ответе, проблема заключается в экземпляре привязки. При определении привязки к GridViewColumn в его шаблоне ячейки я буду использовать конструктор только один раз для каждого столбца. Итак, вопрос в том, как я могу это изменить - возможно ли это вообще?


person ChriPf    schedule 13.03.2017    source источник
comment
Просто идея. Возможно, не используя IMultiValueConverter. Использование IValueConverter и задание плотности в качестве параметра должно работать. Вы можете рассчитать литры из кг и кг из литров.   -  person Mighty Badaboom    schedule 13.03.2017
comment
Вы хотите создать один экземпляр конвертера или нет?   -  person mm8    schedule 13.03.2017
comment
Нет, мне нужны отдельные экземпляры преобразователя. Однако мне кажется, что проблема не в конвертере, а в самой привязке, хотя она и определена в шаблоне ячейки.   -  person ChriPf    schedule 13.03.2017
comment
Пожалуйста, обратитесь к моему ответу за примером того, как вы можете настроить привязку в XAML.   -  person mm8    schedule 13.03.2017
comment
@MightyBadaboom, к сожалению, параметр IValueConverter нельзя установить с помощью привязки.   -  person ChriPf    schedule 13.03.2017
comment
Ах, извините. Это не DependencyProperty, забыл об этом:/   -  person Mighty Badaboom    schedule 13.03.2017


Ответы (2)


Я предполагал, что это приведет к созданию отдельного экземпляра для каждой привязки, но это не так.

Следующее определенно создает новый экземпляр класса MyConverter:

Converter = new MyConverter();

Убедитесь, что вы создаете новый экземпляр класса MyBinding для каждой привязки.

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

<TextBlock>
    <TextBlock.Text>
        <MultiBinding>
            <MultiBinding.Converter>
                <local:MyConverter />
            </MultiBinding.Converter>
            <Binding Path="Test" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>
person mm8    schedule 13.03.2017

Что касается хранения значений в методе ConvertBack: если я вас правильно понял, вы можете использовать Binding.DoNothing в функции ConvertBack. Пример:

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

namespace Example.Converter
{
    public class StringFormatConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            // object[] values per index
            // 0 ... some value 1
            // 1 ... some value 2

            // ... do amazing stuff with values

            return "hello world";
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            try
            {
                // here: don't change source's "some value 1", and assign ToDecimal result to source's "some value 2"
                return new object[] {Binding.DoNothing, System.Convert.ToDecimal(value, culture) };
            }
            catch (Exception e)
            {
                // do not change anything in the source
                return new object[] {Binding.DoNothing, Binding.DoNothing};
            }
        }
    }
}
person Anatoly Vasilyev    schedule 28.08.2018