Прикрепить поведение XAML ко всем элементам управления одного типа
У меня есть InvokeCommandAction
что у меня есть то, что прикреплено к GotFocus
событие TextBox
вот так:
<TextBox Grid.Row="0"
Grid.Column="1"
Width="40"
HorizontalAlignment="Right">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="Enter data [message to be displayed]" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
Это прекрасно работает, но у меня есть десятки TextBox
ES с этой же настройкой. Вместо того, чтобы повторять код (как я сейчас делаю для каждого), я надеюсь просто прикрепить этот триггер ко всем элементам управления типа {x:Type TextBox}
,
Обычно я бы установил свойства в Resources
раздел, как это:
<UserControl.Resources>
<Style TargetType="TextBlock">
<Setter Property="Padding" Value="5,0,0,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</UserControl.Resources>
К сожалению, это не будет работать для Triggers
:
Присоединенное свойство "Триггеры" можно применять только к типам, производным от "DependencyObject".
В идеале я хотел бы сделать что-то вроде этого:
<UserControl.Resources>
<Style TargetType="{x:Type TextBox}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="{Binding Tag}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Style>
</UserControl.Resources>
Где мне тогда просто нужно установить Tag
собственность каждого TextBox
указать сообщение для отображения. Я на правильном пути? Нужно ли изменить его, чтобы использовать ControlTemplate
или что-то типа того?
РЕДАКТИРОВАТЬ
Я видел подобный вопрос здесь: триггеры взаимодействия в стиле в ResourceDictionary WPF
Прочитав ответы на этот вопрос, я попробовал следующее:
<UserControl.Resources>
<TextBox x:Key="TextBoxWithTag">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</UserControl.Resources>
Затем присваиваем элемент управления следующим образом:
<ContentControl Grid.Row="0"
Grid.Column="1"
Width="40"
HorizontalAlignment="Right"
Content="{StaticResource TextBoxWithTag}"
Tag="test tag" />
Это также не работает, все еще жалуясь на:
Присоединенное свойство "Триггеры" можно применять только к типам, производным от "DependencyObject".
РЕДАКТИРОВАТЬ 2
Здесь GotFocusCommand
Информация. Он устанавливает значение string
это имеет TextBlock
связаны с этим.
Это по моему ViewModel
:
private ICommand _gotFocusCommand;
public ICommand GotFocusCommand
{
get
{
if (_gotFocusCommand == null)
{
_gotFocusCommand = new DelegateCommand<string>(TextBoxGotFocus);
}
return _gotFocusCommand;
}
}
private void TextBoxGotFocus(string infoText)
{
CardInfoText = infoText;
}
Тогда XAML:
<TextBlock Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Text="{Binding CardInfoText}" />
1 ответ
Есть несколько способов сделать то, что вы хотите. Один пример:
public static class UIBehaviors {
public static readonly DependencyProperty AttachedTriggersProperty = DependencyProperty.RegisterAttached(
"AttachedTriggers", typeof (EventTriggerCollection), typeof (UIBehaviors), new PropertyMetadata(null, OnAttachedTriggersChanged));
private static void OnAttachedTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var triggers = Interaction.GetTriggers(d);
if (e.OldValue != null) {
foreach (var trigger in (EventTriggerCollection) e.OldValue) {
triggers.Remove(trigger);
}
}
if (e.NewValue != null) {
foreach (var trigger in (EventTriggerCollection) e.NewValue) {
triggers.Add(trigger);
}
}
}
public static void SetAttachedTriggers(DependencyObject element, EventTriggerCollection value) {
element.SetValue(AttachedTriggersProperty, value);
}
public static EventTriggerCollection GetAttachedTriggers(DependencyObject element) {
return (EventTriggerCollection) element.GetValue(AttachedTriggersProperty);
}
}
public class EventTriggerCollection : Collection<EventTrigger> {
}
Здесь мы объявляем вложенное свойство, которое принимает набор EventTrigger (из сборки Interacctivity). Когда это свойство установлено, мы просто присоединяем все эти триггеры, как это делает i:Interaction.Triggers. Тогда используйте это так:
<Window.Resources>
<local:EventTriggerCollection x:Shared="False" x:Key="textBoxTriggers">
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding GotFocusCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TextBox}, Path=Tag}" />
</i:EventTrigger>
</local:EventTriggerCollection>
<Style TargetType="{x:Type TextBox}">
<Setter Property="local:UIBehaviors.AttachedTriggers" Value="{StaticResource textBoxTriggers}"/>
</Style>
</Window.Resources>
Обратите внимание, как я привязываюсь к свойству TextBox.Tag. Вы не можете просто привязать к нему, как в вашем вопросе, потому что ваш контекст данных будет моделью представления (с GotFocusCommand). Также обратите внимание, как коллекция триггеров перемещается как отдельный элемент в словаре ресурсов, и для него устанавливается x:Shared="false". Это приведет к созданию нового набора триггеров при каждом обращении к этому свойству, поэтому каждый TextBox будет иметь свой собственный набор триггеров.
Тогда любой
<TextBox Text="Test" Tag="test message" />
Вызовет GotFocusCommand для контекста данных TextBox с параметром "тестовое сообщение".