处理背后的自定义控制代码中的事件 [英] Handle Events in Custom Control Code Behind
问题描述
好吧,这可能是一个很愚蠢的问题,但我已经搜索了很长时间,但找不到有效的解决方案...
Ok, that probably is a pretty dumb question but I have searched quite a while but could not find a solution for this that works...
我有一个自 Control
继承的自定义控件,其中应包含自动化代码.
I have a Custom control inherited from Control
, which shall include code behind automation.
对于序言,请选择控件 TextBox
的所有文本,或者在更改 TextBox
的内容时生成紧密匹配的列表.
For examble select all text of a controls TextBox
when selected, or generate a list of close matches when the content of that TextBox
is changed.
public class vokDataGridEdit : Control
{
static vokDataGridEdit()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(vokDataGridEdit), new FrameworkPropertyMetadata(typeof(vokDataGridEdit)));
// Events internal to control (??? found on some how-to's)
EventManager.RegisterClassHandler(typeof(vokDataGridEdit), UIElement.GotKeyboardFocusEvent, new RoutedEventHandler(OnSelectContent), true);
}
// Dependecy Properties ...
// The Event that shall Fire when the TextBox gets Focus / Editing Mode
public static void SelectContent(object sender, RoutedEventArgs e)
{
if (sender is TextBox tb)
{
tb.SelectAll();
}
}
}
以及控件样式模板:
<ResourceDictionary xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ccont = "clr-namespace:App.Controls">
<!-- Default style for the Validation Buttons -->
<Style TargetType="{x:Type ccont:vokDataGridEdit}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ccont:vokDataGridEdit}">
<TextBox Text = "{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}}"
BorderThickness = "0"
ContextMenuService.Placement = "Right"
ContextMenuService.PlacementTarget = "{Binding Path=., RelativeSource={RelativeSource Self}}"
GotKeyboardFocus = "SelectContent">
<TextBox.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<Border CornerRadius = "5"
Background = "LightGray"
BorderThickness = "1"
BorderBrush = "Gray"
Padding = "2">
<StackPanel Orientation="Vertical">
<!-- Title -->
<TextBlock Text="Test" />
<!-- TODO: List of matches -->
<TextBox Text = "{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}}"
BorderThickness = "0" />
</StackPanel>
</Border>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
问题1:我如何绑定事件 SelectContent
(要在焦点获得时选择所有 TextBox
内容,nb:这是一部分 CellEditingTemplate
的 DataGrid
)到 GotKeyboardFocus
?在Apps代码中,事件通常正常,但是对于自定义控件而言,它们不起作用,因为样式实际上没有隐藏的代码" ...
Question 1: How can I bind the event SelectContent
(to select all TextBox
content when it get focus, nb: it is part of a DataGrid
for the CellEditingTemplate
) to GotKeyboardFocus
? Events are normaly fine in the Apps code, but for the Custom Control they do not work as there is no "Code Behind" really for the Style...
问题2:假设我有一个包含单词数组的依赖项属性.基于 TextBox
的内容,我想从Dependency属性的Array中选择一些单词,并将它们传递到Custom Control(内容控件)中的 ListBox
ListBox
的列表只能由自定义控件"管理,而不是由使用该控件的任何人管理.关于如何实现此功能,是否存在首选/规范的MVVM模式?
Question 2: Assuming I have a dependency Property containing an array of words. Based on the content of the TextBox
, I would like to select a few words from the Array in the Dependency Property and pass them to a ListBox
in the Custom Control (the Content of the ListBox
shall only be managed by the Custom Control, not by anyone using that control. Is there a prefered/canonical MVVM schema on how to implement this?
推荐答案
部分解决方案:
最后,我在直接控件上得到了要起作用的事件( ContextMenu
中的控件仍然没有EventHandlers ...).
Finaly I got event on the direct controls to work (controls in a ContextMenu
still don't get EventHandlers...).
显然,该点是使用 GetTemplateChild()
以便按名称获取TextBox,然后关联事件处理程序:
Apparently the point was using GetTemplateChild()
in order to get the TextBox by name, and then associate the Event handlers:
<ResourceDictionary xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ccont = "clr-namespace:App.Controls">
<!-- Default style for the Validation Buttons -->
<Style TargetType="{x:Type ccont:vokDataGridEdit}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ccont:vokDataGridEdit}">
<TextBox Text = "{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}}"
BorderThickness = "0"
ContextMenuService.Placement = "Right"
ContextMenuService.PlacementTarget = "{Binding Path=., RelativeSource={RelativeSource Self}}"
x:Name = "TextBox">
<TextBox.ContextMenu>
<ContextMenu x:Name="Menu">
<ContextMenu.Template>
<ControlTemplate>
<Border CornerRadius = "5"
Background = "LightGray"
BorderThickness = "1"
BorderBrush = "Gray"
Padding = "2">
<StackPanel Orientation="Vertical">
<!-- Title -->
<TextBlock Text="Test" x:Name = "Test" />
<!-- TODO: List of matches -->
<TextBox Text = "{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType=ccont:vokDataGridEdit}}"
BorderThickness = "0" />
</StackPanel>
</Border>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
和代码(未显示依赖项属性):
And Code (Dependency Properties not shown):
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace App.Controls
{
/// <summary>
/// DataGrid Edit control (see: https://www.c-sharpcorner.com/article/wpf-routed-events/ for RoutedEvents)
/// </summary>
public class vokDataGridEdit : Control
{
static vokDataGridEdit()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(vokDataGridEdit), new FrameworkPropertyMetadata(typeof(vokDataGridEdit)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Demo purpose only, check for previous instances and remove the handler first
if (this.GetTemplateChild("TextBox") is TextBox button)
{
button.PreviewMouseLeftButtonDown += this.SelectContentPreparation;
button.GotKeyboardFocus += this.SelectContent;
button.MouseDoubleClick += this.SelectContent;
//button.GotFocus += this.SelectContent;
}
}
/// <summary>
/// Prepare the Control to ensure it has focus before subsequent event fire
/// </summary>
private void SelectContentPreparation(object sender, MouseButtonEventArgs e)
{
if (sender is TextBox tb)
{
if (!tb.IsKeyboardFocusWithin)
{
e.Handled = true;
tb.Focus();
}
}
}
private void SelectContent(object sender, RoutedEventArgs e)
{
if (sender is TextBox tb)
{
e.Handled = true;
tb.SelectAll();
}
}
}
}
这篇关于处理背后的自定义控制代码中的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!