Могу ли я изменить свойства привязки в DataTrigger, не зная самой привязки? - PullRequest
10 голосов
/ 03 февраля 2012

У меня есть стиль TextBox, который форматирует число, если поле не сфокусировано, но оставляет число неформатированным, пока оно редактируется.

Это стиль, который я хочу для текстовых ящиков с несколькими номерами, но все онисодержат разные текстовые привязки.Единственное отличие между обычным установщиком текста и установщиком триггерного текста заключается в том, что у триггера есть привязка StringFormat=N2.

Есть ли способ сделать этот стиль универсальным, например изменить только StringFormat свойство привязки в DataTrigger?

<TextBox>
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
                <Setter Property="Text" Value="{Binding SomeValue, StringFormat=N2, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
            <Style.Triggers>
                <Trigger Property="IsKeyboardFocusWithin" Value="True">
                    <Setter Property="Text" Value="{Binding SomeValue, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

Ответы [ 5 ]

3 голосов
/ 11 февраля 2012

Есть ли способ сделать этот стиль общим, например, только изменение свойство StringFormat привязки в DataTrigger?

Наследует Style и новый XAML станет таким:

 <TextBox>
    <TextBox.Style>
        <local:FlyingStyle Binding="{Binding ElementName=This, Path=SomeValue}" StringFormat="F2" />
    </TextBox.Style>
 </TextBox>

Вот класс ...

public class FlyingStyle : Style
{
    public FlyingStyle()
        : base(typeof(TextBox))
    { }

    string _stringFormat;
    public string StringFormat
    {
        get { return _stringFormat; }
        set
        {
            _stringFormat = value;
            CheckInitialize();
        }
    }
    Binding _binding;
    public Binding Binding
    {
        get { return _binding; }
        set
        {
            _binding = value;
            CheckInitialize();
        }
    }
    void CheckInitialize()
    {
        if (StringFormat == null || Binding == null) { return; }// need both

        Setters.Add(CreateSetter(Binding, StringFormat));

        var trigger = new Trigger
        {
            Property = UIElement.IsKeyboardFocusWithinProperty,
            Value = true,
        };
        trigger.Setters.Add(CreateSetter(Binding));
        Triggers.Add(trigger);
    }

    /// <summary>Creates the common <see cref="Setter"/>.</summary>
    static Setter CreateSetter(Binding binding, string stringFormat = null)
    {
        // must create a copy, because same binding ref but diff StringFormats
        var bindingCopy = new Binding
        {
            // these could be copies as well
            UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
            ValidatesOnDataErrors = true,
            Mode = BindingMode.TwoWay,
            Path = binding.Path,

            AsyncState = binding.AsyncState,
            BindingGroupName = binding.BindingGroupName,
            BindsDirectlyToSource = binding.BindsDirectlyToSource,
            Converter = binding.Converter,
            ConverterCulture = binding.ConverterCulture,
            ConverterParameter = binding.ConverterParameter,
            ElementName = binding.ElementName,
            FallbackValue = binding.FallbackValue,
            IsAsync = binding.IsAsync,
            NotifyOnSourceUpdated = binding.NotifyOnSourceUpdated,
            NotifyOnTargetUpdated = binding.NotifyOnTargetUpdated,
            NotifyOnValidationError = binding.NotifyOnValidationError,
            //StringFormat = set below...
            TargetNullValue = binding.TargetNullValue,
            UpdateSourceExceptionFilter = binding.UpdateSourceExceptionFilter,
            ValidatesOnExceptions = binding.ValidatesOnExceptions,
            XPath = binding.XPath,
            //ValidationRules = binding.ValidationRules
        };
        // mutex ElementName, so modify if needed
        // Source = binding.Source,
        // RelativeSource = binding.RelativeSource,

        if (stringFormat != null)
        {
            bindingCopy.StringFormat = stringFormat;
        }
        return new Setter(TextBox.TextProperty, bindingCopy);
    }
}

Обратите внимание, что мой тест был

  • универсальное MainWindow
  • подразумевается INotifyPropertyChanged
  • SomeValue свойство INPC
  • DataContext = this
  • x: Имя = Это
2 голосов
/ 11 февраля 2012

Моя попытка решить эту проблему закончилась пользовательским элементом управления и мульти-связыванием, оба из которых были предложены выше.

Это позволило мне использовать разметку следующим образом:

Я пытался опубликовать свой код, но получаю сообщение об ошибке "код, который неправильно отформатирован как код".

2 голосов
/ 09 февраля 2012

Единственный вариант, который я вижу, это создать прикрепленное свойство для StringFormat и использовать multiBinding.

Не совсем то, что вы хотели, но, я думаю, достаточно близко ...

у вас есть больше информации по этому (вроде дубликату) вопроса по SO:

Изменение параметров текстовой привязки TextBox с помощью стиля

0 голосов
/ 06 февраля 2012

К сожалению, это (насколько мне известно) невозможно.Одним из возможных обходных путей может быть программное создание такого стиля на лету, который может быть заключен в MarkupExtension, который принимает путь в качестве параметра конструктора.

0 голосов
/ 03 февраля 2012

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

Это может привести к циклической привязке, хотя, когда редактирование не имеет фокуса, не знаю, как WPF реагирует в таких ситуациях.

...