WPF За экземпляр привязки преобразователя значений? - PullRequest
4 голосов
/ 02 марта 2011

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

Ответы [ 5 ]

17 голосов
/ 02 марта 2011

Вам необходимо указать x:Shared="False" на ресурсе конвертера. Вот пример:

<BooleanToVisibilityConverter x:Key="MyConverter" x:Shared="False"/>
3 голосов
/ 02 марта 2011

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

   <TextBox>
        <TextBox.Resources>
            <Converters:VisibilityConverter x:Key="conv"/>
        </TextBox.Resources>
        <TextBox.Text>
            <Binding Converter="{StaticResource conv}"/>
        </TextBox.Text>
    </TextBox>
1 голос
/ 02 марта 2011

Почему? Он должен быть детерминированным и не знать о каком-либо состоянии, кроме того, которое передается ему через его параметры. Я использовал преобразователи значений для хранения статического списка изображений (значение преобразуется в изображение), и это прекрасно работает, даже если один и тот же преобразователь используется для нескольких столбцов в сетке данных с тысячами строк. (Обратите внимание, что преобразователь все еще не знает о каком-либо внешнем состоянии).

В любом случае, посмотрите, ответит ли это на ваш вопрос: Являются ли преобразователи значений созданными для привязки в WPF?

0 голосов
/ 14 сентября 2016

Наследуйте от MarkupExtension, а затем создайте конвертер в конструкторе.

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        _converter = new FlagsToBoolConverter();
        return _converter;
    }

Вот полный пример. Это конвертер флагов, который необходимо создать для сохранения исходного значения ConvertBack.

using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace Something
{
    public class FlagsToBoolConverter : MarkupExtension, IValueConverter
    {
        private FlagsToBoolConverter _converter;

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            _converter = new FlagsToBoolConverter();
            return _converter;
        }

        private ulong _sourceValue;

        public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                var type = value.GetType();
                if (type.IsEnum)
                {
                    ulong mask = (ulong)System.Convert.ChangeType(Enum.Parse(type, (string)parameter), typeof(ulong));
                    _sourceValue = (ulong)System.Convert.ChangeType(Enum.Parse(type, value.ToString()), typeof(ulong));
                    return ((mask & _sourceValue) != 0);
                }
                return value;
            }
            catch (Exception ex)
            {
                Console.WriteLine("FlagsEnumValueConverter: Invalid Cast(to) Value={0} Type={1} Param={2} Exception{3}", value, targetType, parameter, ex);
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                if (targetType.IsEnum)
                {
                    var original = this._sourceValue;
                    var originalEnum = Enum.Parse(targetType, original.ToString());
                    var maskEnum = Enum.Parse(targetType, (string)parameter);
                    var mask = (ulong)System.Convert.ChangeType(maskEnum, typeof(ulong));
                    _sourceValue ^= mask;
                    var sourceEnum = Enum.Parse(targetType, _sourceValue.ToString());
                    Console.WriteLine($"Modified Value: {original} ({originalEnum}) by Mask {mask} ({maskEnum}) Result = {_sourceValue} ({sourceEnum})");
                    return sourceEnum;
                }
                return value;
            }
            catch (Exception ex)
            {
                Console.WriteLine("FlagsEnumValueConverter: Invalid Cast(from) Value={0} Type={1} Param={2} Exception{3}", value, targetType, parameter, ex);
            }
            return value;
        }
    }
}

Ваш префикс должен быть объявлен xmlns:src="clr-namespace:Something". И тогда в вашей привязке замените нормальный конвертер на Converter={src:FlagsToBoolConverter}

  <CheckBox IsChecked="{Binding SomeFlagsEnum, ConverterParameter=FlagA, Converter={src:FlagsToBoolConverter}}">FlagA</CheckBox>
  <CheckBox IsChecked="{Binding SomeFlagsEnum, ConverterParameter=FlagB, Converter={src:FlagsToBoolConverter}}">FlagB</CheckBox>
  <CheckBox IsChecked="{Binding SomeFlagsEnum, ConverterParameter=FlagC, Converter={src:FlagsToBoolConverter}}">FlagC</CheckBox>
0 голосов
/ 29 июня 2014

Если вы помещаете ваши конвертеры в ресурсы и ссылаетесь на них с помощью поиска {StaticResource ConverterName}, то они создаются только один раз для каждого экземпляра словаря ресурсов.

Но лучшим подходом является наследование ваших конвертеров от MarkupExtension и используйте их напрямую, вместо добавления их к ресурсам и ссылки на них.

Вот пример такого базового класса:

http://www.snippetsource.net/Snippet/18/base-class-for-valueconverters-in-wpf

Привет Кристиан

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