使用 Caliburn Micro 从 DataGridComboBoxColumn 捕获 TextChanged 事件
Capturing TextChanged event from DataGridComboBoxColumn using Caliburn Micro
我在将 ComboBox
的 TextBox
部分的 TextChanged
事件传递给关联的视图模型时遇到问题。
符合预期:
- 在
TextChanged
上调用后面代码中的 OnTextChanged()
方法。
- 在
KeyUp
上,调用了视图模型中的 OnKeyUp()
方法。
但是:
- 在
TextChanged
上,未调用视图模型中的 OnTextChanged()
方法。
为什么没有调用它,我该如何解决?
<UserControl x:Class="AutoComplete.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<UserControl.Resources>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
</UserControl.Resources>
<Grid>
<ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"/>
<DataGrid ItemsSource="{Binding Rows}" AutoGenerateColumns="False" CanUserAddRows="True" CanUserDeleteRows="True">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Code">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<EventSetter Event="TextBoxBase.TextChanged" Handler="OnTextChanged"/>
<Setter Property="cal:Action.TargetWithoutContext" Value="{Binding DataContext, Source={StaticResource ProxyElement}}"/>
<Setter Property="cal:Message.Attach" Value="[Event TextBoxBase.TextChanged] = [Action OnTextChanged($source, $dataContext)]; [Event KeyUp] = [Action OnKeyUp()]"/>
<Setter Property="IsEditable" Value="True"/>
<Setter Property="ItemsSource" Value="{Binding DataContext.Suggestions, Source={StaticResource ProxyElement}}"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
这不起作用,因为 Caliburn Micro 默认使用 EventTrigger
class 作为 Message.Attach
。根据 this post EventTrigger
使用反射使用 EventName
属性 查找事件失败,因为 ComboBox
没有公开名为 TextBoxBase.TextChanged
的事件.它也没有公开 TextChanged
事件,它是 TextChanged
从应该被捕获的 ComboBox
的 TextBox
组件冒出来的。
以上post也提供了一种适应性强的解决方案。首先创建一个新的 RoutedEventTrigger
class:
public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
public RoutedEvent RoutedEvent { get; set; }
protected override void OnAttached()
{
var element = (AssociatedObject as Behavior as IAttachedObject)?.AssociatedObject as UIElement
?? AssociatedObject as UIElement;
element?.AddHandler(RoutedEvent, new RoutedEventHandler(OnRoutedEvent));
}
void OnRoutedEvent(object sender, RoutedEventArgs args)
{
OnEvent(args);
}
protected override string GetEventName()
{
return RoutedEvent.Name;
}
}
然后将 Caliburn Micro 配置为在可能的情况下使用 RoutedEventTrigger 而不是 EventTrigger:
public class Bootstrapper : BootstrapperBase
{
public Bootstrapper()
{
Initialize();
}
private RoutedEventTrigger CreateRoutedEventTrigger(DependencyObject target, string routedEvent)
{
var routedEvents = EventManager.GetRoutedEvents().ToDictionary(r => $"{r.OwnerType.Name}.{r.Name}");
if (routedEvents.ContainsKey(routedEvent))
{
var trigger = new RoutedEventTrigger
{
RoutedEvent = routedEvents[routedEvent]
};
trigger.Attach(target);
return trigger;
}
return null;
}
protected override void OnStartup(object sender, StartupEventArgs args)
{
var baseCreateTrigger = Parser.CreateTrigger;
Parser.CreateTrigger = (target, triggerText) =>
{
var baseTrigger = baseCreateTrigger(target, triggerText);
var baseEventTrigger = baseTrigger as EventTrigger;
return CreateRoutedEventTrigger(target, baseEventTrigger?.EventName ?? "") ?? baseTrigger;
};
...
}
...
}
此设置后可以使用冒泡 RoutedEvents。
我在将 ComboBox
的 TextBox
部分的 TextChanged
事件传递给关联的视图模型时遇到问题。
符合预期:
- 在
TextChanged
上调用后面代码中的OnTextChanged()
方法。 - 在
KeyUp
上,调用了视图模型中的OnKeyUp()
方法。
但是:
- 在
TextChanged
上,未调用视图模型中的OnTextChanged()
方法。
为什么没有调用它,我该如何解决?
<UserControl x:Class="AutoComplete.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<UserControl.Resources>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
</UserControl.Resources>
<Grid>
<ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"/>
<DataGrid ItemsSource="{Binding Rows}" AutoGenerateColumns="False" CanUserAddRows="True" CanUserDeleteRows="True">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Code">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<EventSetter Event="TextBoxBase.TextChanged" Handler="OnTextChanged"/>
<Setter Property="cal:Action.TargetWithoutContext" Value="{Binding DataContext, Source={StaticResource ProxyElement}}"/>
<Setter Property="cal:Message.Attach" Value="[Event TextBoxBase.TextChanged] = [Action OnTextChanged($source, $dataContext)]; [Event KeyUp] = [Action OnKeyUp()]"/>
<Setter Property="IsEditable" Value="True"/>
<Setter Property="ItemsSource" Value="{Binding DataContext.Suggestions, Source={StaticResource ProxyElement}}"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
这不起作用,因为 Caliburn Micro 默认使用 EventTrigger
class 作为 Message.Attach
。根据 this post EventTrigger
使用反射使用 EventName
属性 查找事件失败,因为 ComboBox
没有公开名为 TextBoxBase.TextChanged
的事件.它也没有公开 TextChanged
事件,它是 TextChanged
从应该被捕获的 ComboBox
的 TextBox
组件冒出来的。
以上post也提供了一种适应性强的解决方案。首先创建一个新的 RoutedEventTrigger
class:
public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
public RoutedEvent RoutedEvent { get; set; }
protected override void OnAttached()
{
var element = (AssociatedObject as Behavior as IAttachedObject)?.AssociatedObject as UIElement
?? AssociatedObject as UIElement;
element?.AddHandler(RoutedEvent, new RoutedEventHandler(OnRoutedEvent));
}
void OnRoutedEvent(object sender, RoutedEventArgs args)
{
OnEvent(args);
}
protected override string GetEventName()
{
return RoutedEvent.Name;
}
}
然后将 Caliburn Micro 配置为在可能的情况下使用 RoutedEventTrigger 而不是 EventTrigger:
public class Bootstrapper : BootstrapperBase
{
public Bootstrapper()
{
Initialize();
}
private RoutedEventTrigger CreateRoutedEventTrigger(DependencyObject target, string routedEvent)
{
var routedEvents = EventManager.GetRoutedEvents().ToDictionary(r => $"{r.OwnerType.Name}.{r.Name}");
if (routedEvents.ContainsKey(routedEvent))
{
var trigger = new RoutedEventTrigger
{
RoutedEvent = routedEvents[routedEvent]
};
trigger.Attach(target);
return trigger;
}
return null;
}
protected override void OnStartup(object sender, StartupEventArgs args)
{
var baseCreateTrigger = Parser.CreateTrigger;
Parser.CreateTrigger = (target, triggerText) =>
{
var baseTrigger = baseCreateTrigger(target, triggerText);
var baseEventTrigger = baseTrigger as EventTrigger;
return CreateRoutedEventTrigger(target, baseEventTrigger?.EventName ?? "") ?? baseTrigger;
};
...
}
...
}
此设置后可以使用冒泡 RoutedEvents。