Wpf 在自定义控件代码中处理事件
好的,这可能是一个相当愚蠢的问题,但我已经搜索了相当长的时间,但找不到一个有效的解决方案 我有一个从Wpf 在自定义控件代码中处理事件,wpf,events,automation,custom-controls,code-behind,Wpf,Events,Automation,Custom Controls,Code Behind,好的,这可能是一个相当愚蠢的问题,但我已经搜索了相当长的时间,但找不到一个有效的解决方案 我有一个从控件继承的自定义控件,其中应包括代码隐藏自动化 例如,选中时选择控件TextBox的所有文本,或在更改该TextBox的内容时生成一个密切匹配的列表 public class vokDataGridEdit : Control { static vokDataGridEdit() { DefaultStyleKeyProperty.OverrideMetadata(
控件
继承的自定义控件,其中应包括代码隐藏自动化
例如,选中时选择控件TextBox
的所有文本,或在更改该TextBox
的内容时生成一个密切匹配的列表
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:我如何将事件选择内容
(要在获得焦点时选择所有文本框
内容,请注意:它是CellEditingTemplate
的数据网格
的一部分)绑定到GotKeyboardFocus
?事件在应用程序代码中通常很好,但对于自定义控件,它们不起作用,因为样式没有真正的“代码隐藏”
问题2:假设我有一个包含单词数组的依赖属性。根据
文本框
的内容,我想从Dependency属性的数组中选择一些单词,并将它们传递给自定义控件中的列表框
(列表框的内容只能由自定义控件管理,不能由使用该控件的任何人管理。是否有首选/规范的MVVM模式来实现此功能?通常您应该只发布一个问题,而不是多个问题。对于第一个问题,您可以在中使用事件设置器,例如隐式样式ode>UserControl
的资源:
<Style TargetType="TextBox">
<EventSetter Event="GotKeyboardFocus" Handler="SelectContent"/>
</Style>
在XAML中使用此行为:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<TextBox Text="Some text">
<i:Interaction.Behaviors>
<local:SelectAllBehavior/>
</i:Interaction.Behaviors>
</TextBox>
xmlns:i=“clr命名空间:System.Windows.Interactivity;assembly=System.Windows.Interactivity”
部分解决方案:
最后,我让direct控件上的事件正常工作(上下文菜单中的控件仍然没有获得EventHandler…)
显然,关键是使用GetTemplateChild()
按名称获取文本框,然后关联事件处理程序:
<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>
和代码(未显示依赖项属性):
使用系统;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Input;
使用System.Windows.Media;
命名空间应用程序控件
{
///
///DataGrid编辑控件(请参阅:https://www.c-sharpcorner.com/article/wpf-routed-events/ 对于路由事件)
///
公共类vokDataGridEdit:控件
{
静态vokDataGridEdit()
{
OverrideMetadata(typeof(vokDataGridEdit)、new FrameworkPropertyMetadata(typeof(vokDataGridEdit));
}
应用程序模板()上的公共重写无效
{
base.OnApplyTemplate();
//仅用于演示目的,请检查以前的实例并首先删除处理程序
如果(这个.GetTemplateChild(“TextBox”)是TextBox按钮)
{
button.PreviewMouseLeftButtonDown+=此。选择内容准备;
button.GotKeyboardFocus+=this.SelectContent;
button.MouseDoubleClick+=此.SelectContent;
//button.GotFocus+=this.SelectContent;
}
}
///
///准备控件,以确保其在后续事件触发前具有焦点
///
private void SelectContentPreparation(对象发送者,鼠标按钮ventargs e)
{
如果(发送方为文本框tb)
{
如果(!tb.IsKeyboardFocusWithin)
{
e、 已处理=正确;
tb.Focus();
}
}
}
私有void SelectContent(对象发送方、路由目标方)
{
如果(发送方为文本框tb)
{
e、 已处理=正确;
tb.SelectAll();
}
}
}
}
Hi Rekshino,我将样式添加到文本框中,但构建失败,声称它需要x:Class
指令,而且无论如何,处理程序将被标记为在设计器中找不到…代码请参见问题。查看我的答案,将其放到UserControl
的资源中。处理程序也必须位于UserControl
中。如果我没有找到,请原谅我很理解。但是这个控件是一个自定义控件,样式在Generic.xaml
中,而不是UserControl
中,带有代码隐藏。因此我没有UserCon
<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>
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();
}
}
}
}