Я знаю, что могу создать сеттер, который проверяет, равно ли значение NULL, и что-то делает. Пример:
<TextBlock>
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding = "{Binding SomeField}" Value = "{x:Null}">
<Setter Property = "TextBlock.Text" Value = "It's NULL Baby!" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Но как я могу проверить значение "не" ... например, "NOT NULL" или "NOT = 3"? Возможно ли это в XAML?
Полученные результаты: Спасибо за ваши ответы ... Я знал, что могу сделать преобразователь значений (что означает, что мне придется использовать код, и это не будет чистый XAML, как я надеялся). Однако это действительно отвечает на вопрос, что фактически «нет», вы не можете сделать это в чистом XAML. Однако выбранный ответ показывает, вероятно, лучший способ Создайте такой функциональности. Хорошая находка.





Я столкнулся с аналогичным ограничением с DataTriggers, и казалось бы, можно только проверить на равенство. Самое близкое, что я видел, что могло бы вам помочь, - это техника выполнения других типов сравнений, отличных от равенства.
Это сообщение в блоге описывает, как выполнять сравнения, такие как LT, GT и т. д. В DataTrigger.
Это ограничение DataTrigger можно в некоторой степени обойти, используя Converter для преобразования данных в специальное значение, с которым вы затем можете сравнивать, как это предлагается в ответе Роберта Макни.
Для этого можно использовать IValueConverter:
<TextBlock>
<TextBlock.Resources>
<conv:IsNullConverter x:Key = "isNullConverter"/>
</TextBlock.Resources>
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding = "{Binding SomeField, Converter = {StaticResource isNullConverter}}" Value = "False">
<Setter Property = "TextBlock.Text" Value = "It's NOT NULL Baby!"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Где IsNullConverter определен в другом месте (и conv настроен для ссылки на его пространство имен):
public class IsNullConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value == null);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
}
}
Более общим решением было бы реализовать IValueConverter, который проверяет равенство с ConverterParameter, чтобы вы могли проверять что угодно, а не только null.
Я полагаю, вы могли бы сделать преобразователь более универсальным и использовать ConverterParameter для передачи значения для сравнения (чтобы поддерживать оба сравнения с NOT null и NOT 3.
Это сработало для меня - использование множественного триггера делает его приятным и мощным.
Это немного обман, но я просто установил стиль по умолчанию, а затем переопределил его с помощью DataTrigger, если значение равно нулю ...
<Style>
<!-- Highlight for Reviewed (Default) -->
<Setter Property = "Control.Background" Value = "PaleGreen" />
<Style.Triggers>
<!-- Highlight for Not Reviewed -->
<DataTrigger Binding = "{Binding Path=REVIEWEDBY}" Value = "{x:Null}">
<Setter Property = "Control.Background" Value = "LightIndianRed" />
</DataTrigger>
</Style.Triggers>
</Style>
Это было лучшее решение для моего сценария! Спасибо за такой ответ!
Не думаю, что это хакерство, на это нужно много времени; и это наиболее чистый способ сделать это.
Сеттер по умолчанию можно использовать без тега Style.Setter.
Просто билет! Я продолжал устанавливать значение по умолчанию в элементе управления, который владеет стилем, и не мог понять, почему он продолжал переопределять мои стили :-) Спасибо!
лучше ответить, чем использовать конвертер ... простой и чистый.
Спасибо! Это просто и эффективно. Как раз то, что мне нужно.
Это не чит. Вот как это сделать.
Это может привести к ошибкам привязки в окне вывода, если стиль / свойство по умолчанию зависит от того, что данные не равны нулю ...
Я использую это, только чтобы включить кнопку, если выбран элемент списка (т.е. не null):
<Style TargetType = "{x:Type Button}">
<Setter Property = "IsEnabled" Value = "True"/>
<Style.Triggers>
<DataTrigger Binding = "{Binding ElementName=lvMyList, Path=SelectedItem}" Value = "{x:Null}">
<Setter Property = "IsEnabled" Value = "False"/>
</DataTrigger>
</Style.Triggers>
</Style>
Иногда самое простое решение скрыто на виду. Я считаю, что код XAML интерпретируется сверху вниз. Таким образом, кнопка сначала будет включена, а затем отключена, если в списке не выбран ни один элемент. Но, пожалуйста, скажите мне, обновляется ли стиль после выбора элемента в списке?
Кнопка активна, когда выбран элемент списка, да.
Мое решение находится в экземпляре DataContext (или ViewModel при использовании MVVM). Я добавляю свойство, которое возвращает true, если выполняется условие Not Null, которое я хочу.
Public ReadOnly Property IsSomeFieldNull() As Boolean
Get
Return If(SomeField is Null, True, False)
End Get
End Property
и привяжите DataTrigger к указанному выше свойству. Примечание. В VB.NET обязательно используйте оператор If, а НЕ функцию IIf, которая не работает с объектами Null. Тогда XAML:
<DataTrigger Binding = "{Binding IsSomeFieldNull}" Value = "False">
<Setter Property = "TextBlock.Text" Value = "It's NOT NULL Baby!" />
</DataTrigger>
Сравните с нулем (как сказал Майкл Нунан):
<Style>
<Style.Triggers>
<DataTrigger Binding = "{Binding SomeProperty}" Value = "{x:Null}">
<Setter Property = "Visibility" Value = "Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
Сравните с ненулевым (без конвертера):
<Style>
<Setter Property = "Visibility" Value = "Collapsed" />
<Style.Triggers>
<DataTrigger Binding = "{Binding SomeProperty}" Value = "{x:Null}">
<Setter Property = "Visibility" Value = "Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
Это, безусловно, самый прямой ответ. Мне это нравится!
Конвертер:
public class NullableToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Collapsed : Visibility.Visible;
}
}
Привязка:
Visibility = "{Binding PropertyToBind, Converter = {StaticResource nullableToVisibilityConverter}}"
Вы можете использовать класс DataTrigger в Microsoft.Expression.Interactions.dll, который поставляется с Смесь выражений.
Пример кода:
<i:Interaction.Triggers>
<i:DataTrigger Binding = "{Binding YourProperty}" Value = "{x:Null}" Comparison = "NotEqual">
<ie:ChangePropertyAction PropertyName = "YourTargetPropertyName" Value = "{Binding YourValue}"/>
</i:DataTrigger
</i:Interaction.Triggers>
Используя этот метод, вы также можете запускать GreaterThan и LessThan.
Чтобы использовать этот код, вы должны сослаться на две библиотеки DLL:
System.Windows.Interactivity.dll
Microsoft.Expression.Interactions.dll
<StackPanel.Style>
<Style>
<Setter Property = "StackPanel.Visibility" Value = "Visible"></Setter>
<Style.Triggers>
<DataTrigger Binding = "{Binding ElementName=ProfileSelectorComboBox, Path=SelectedItem.Tag}" Value = "{x:Null}">
<Setter Property = "StackPanel.Visibility" Value = "Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
Я просто использовал обратную логику здесь ... сделав мою панель стека невидимой, когда мой комбоэлемент не заполнен, это работает очень хорошо!
Стоп! Нет конвертера! Я не хочу «продавать» библиотеку этого парня, но мне не нравился факт создания конвертера каждый раз, когда я хотел сравнить вещи в XAML.
Итак, с этой библиотекой: https://github.com/Alex141/CalcBinding
вы можете сделать это [и многое другое]:
Во-первых, в объявлении windows / userControl:
<Windows....
xmlns:conv = "clr-namespace:CalcBinding;assembly=CalcBinding"
>
затем в текстовом блоке
<TextBlock>
<TextBlock.Style>
<Style.Triggers>
<DataTrigger Binding = "{conv:Binding 'MyValue==null'}" Value = "false">
<Setter Property = "Background" Value = "#FF80C983"></Setter>
</DataTrigger>
</Style.Triggers>
</TextBlock.Style>
</TextBlock>
Магическая часть - это conv: Привязка 'MYValue == null'. Фактически, вы можете установить любое условие, какое захотите [см. Документ].
обратите внимание, что я не являюсь поклонником третьей стороны. но эта библиотека бесплатна и мало влияет (просто добавьте в проект 2 .dll).
Вы можете использовать конвертер или создать новое свойство в вашей ViewModel следующим образом:
public bool CanDoIt
{
get
{
return !string.IsNullOrEmpty(SomeField);
}
}
и используйте это:
<DataTrigger Binding = "{Binding SomeField}" Value = "{Binding CanDoIt}">
Если вы ищете решение, в котором не используется IValueConverter, вы всегда можете воспользоваться механизмом ниже.
<StackPanel>
<TextBlock Text = "Border = Red when null value" />
<Border x:Name = "border_objectForNullValueTrigger" HorizontalAlignment = "Stretch" Height = "20">
<Border.Style>
<Style TargetType = "Border">
<Setter Property = "Background" Value = "Black" />
<Style.Triggers>
<DataTrigger Binding = "{Binding ObjectForNullValueTrigger}" Value = "{x:Null}">
<Setter Property = "Background" Value = "Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<TextBlock Text = "Border = Green when not null value" />
<Border HorizontalAlignment = "Stretch" Height = "20">
<Border.Style>
<Style TargetType = "Border">
<Setter Property = "Background" Value = "Green" />
<Style.Triggers>
<DataTrigger Binding = "{Binding Background, ElementName=border_objectForNullValueTrigger}" Value = "Red">
<Setter Property = "Background" Value = "Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<Button Content = "Invert Object state" Click = "Button_Click_1"/>
</StackPanel>
Достаточно интересно, что DataTrigger на самом деле имеет внутреннее поле, которое контролирует, проверяет ли он равенство или нет. К сожалению, чтобы добраться до нужного поля, вам придется поразмыслить над этим. Проблема в том, что он может сломаться в следующей версии .net.