Использование привязки для свойства Value условия DataTrigger - PullRequest
24 голосов
/ 11 февраля 2010

Я работаю над приложением WPF и борюсь с триггером данных. Я хотел бы привязать значение условия триггера к некоторому объекту, который у меня есть:

<DataTrigger Binding="{Binding Foo}" 
             Value="{Binding ElementName=AnotherElement, Path=Bar}">..

Однако мне не разрешено, поскольку невозможно использовать привязки для свойства Value. Это? Могу ли я достичь этого как-нибудь? Я получаю следующую ошибку:

Невозможно установить привязку в свойстве «Значение» типа «DataTrigger». «Связывание» может быть установлено только для свойства DependencyObject объекта Dependency.

Ответы [ 3 ]

37 голосов
/ 11 февраля 2010

Нет, это невозможно. Как говорится в сообщении об ошибке, цели привязок WPF могут быть только свойствами зависимостей, а DataTrigger.Value не является свойством зависимостей. Поэтому вам нужно будет присвоить фактическое значение.

Обходной путь должен использовать MultiBinding, чьи дочерние привязки - это две привязки, которые вы хотите сравнить, с IMultiValueConverter, который возвращает true, если два входа равны, и false, если они неравны. Затем DataTrigger может использовать эту MultiBinding и значение True.

6 голосов
/ 20 июля 2018

Вот пример с конвертером IMultiValueConverter.

В этом XAML есть три флажка. Первые два связаны со свойствами Foo и Bar (оба являются логическими). Третий использует множественное связывание с IMultiValueConverter. Проверяется, когда Foo и Bar имеют одинаковые значения.
<!-- It's expected that the DataContext of this StackPanel has boolean Bar and Foo properties.. -->
<StackPanel Orientation="Vertical">
    <StackPanel.Resources>
        <!-- local contains the MultiValueEqualityConverter class implementation -->
        <local:MultiValueEqualityConverter x:Key="multiValueEqualityConverter"/>
    </StackPanel.Resources>

    <CheckBox IsChecked="{Binding Foo}">Foo</CheckBox>
    <CheckBox IsChecked="{Binding Bar}">Bar</CheckBox>

    <CheckBox IsEnabled="False" Content="Are the same">
        <CheckBox.Style>
            <Style TargetType="CheckBox">
                <Style.Setters>
                    <Setter Property="IsChecked" Value="False"/>
                </Style.Setters>
                <Style.Triggers>
                    <DataTrigger Value="True">
                        <DataTrigger.Binding>
                            <MultiBinding Converter="{StaticResource multiValueEqualityConverter}">
                                <Binding RelativeSource="{RelativeSource self}" Path="DataContext.Foo" Mode="OneWay" />
                                <Binding RelativeSource="{RelativeSource self}" Path="DataContext.Bar" Mode="OneWay"/>
                            </MultiBinding>
                        </DataTrigger.Binding>
                        <Setter Property="IsChecked" Value="True" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </CheckBox.Style>
    </CheckBox>
</StackPanel>

Простая IMultiValueConverter реализация для односторонней привязки:

public class MultiValueEqualityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values?.All(o => o?.Equals(values[0]) == true) == true || values?.All(o => o == null) == true;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
1 голос
/ 26 декабря 2018

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

Сделайте модель для каждого предмета, а не сравнивайте ее.

Например, у меня обычно есть стек строк в ItemsControl.DataTemplate. Я пытаюсь установить IsEnabled (или что-то еще), используя DataTrigger, сравнивая с динамическим Value={Binding}.

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

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

Я использую их для ItemsControl.Source, потом удивляюсь, почему я не просто сделал это для начала.

...