另一个类中的 WPF 事件处理程序

问题描述 投票:0回答:3

我为一些自定义 WPF 控件构建了一系列事件处理程序。该事件根据包含的数据类型(电话号码、邮政编码、货币价值等)处理用户输入或离开文本框时显示的文本格式

现在,我将 C# 代码中的所有本地事件直接附加到 xaml。因为我开发了一个可以控件,这意味着逻辑会重复很多次,如果我想更改程序范围的功能,我就必须在事件代码所在的所有地方进行更改。

我确信有一种方法可以将我的所有事件处理程序放在一个类中。谁能帮我指出正确的方向?

我看到了这篇文章:事件处理程序位于与 MainWindow 不同的类中但我不确定它是否与我正在做的事情直接相关。我宁愿对现有的逻辑进行一些小的改变,因为它有效,然后将所有内容重写为命令。

如果可能的话,我基本上想要这样的东西:

LostFocus="ExpandedTextBoxEvents.TextBox_LostFocus"

做这样的事情很容易:

private void TextBoxCurrencyGotFocus(object sender, RoutedEventArgs e)
{
    ExpandedTextBoxEvents.TextBoxCurrencyGotFocus(sender, e);
}
private void TextBoxCurrencyLostFocus(object sender, RoutedEventArgs e)
{
    ExpandedTextBoxEvents.TextBoxCurrencyLostFocus(sender, e);
}

但这不太优雅。

c# wpf events event-handling
3个回答
2
投票

附加属性是实现您想要的效果的一种方法。我经常使用它们。

附上房产代码:

Public Class TextBoxFormatter

    ' ------------------------------------------------------
    ' Define the FormatType attached property

    Public Shared ReadOnly FormatTypeProperty As DependencyProperty = _
        DependencyProperty.RegisterAttached( _
            name:="FormatType", _
            propertyType:=GetType(TextBoxFormatterType), _
            ownerType:=GetType(TextBoxFormatter), _
            defaultMetadata:=New FrameworkPropertyMetadata( _
                defaultValue:=TextBoxFormatterType.None, _
                PropertyChangedCallback:=New PropertyChangedCallback(AddressOf FormatTypePropertyChanged) _
            ) _
        )
    ' ------------------------------------------------------
    ' Define the "getter" and "setter" for FormatType
    Public Shared Function GetFormatType(ByVal target As DependencyObject) As TextBoxFormatterType
        target.GetValue(FormatTypeProperty)
    End Function
    Public Shared Sub SetFormatType(ByVal target As DependencyObject, ByVal value As TextBoxFormatterType)
        target.SetValue(FormatTypeProperty, value)
    End Sub

    ' ------------------------------------------------------
    ' Define the FormatType "PropertyChanged" event handler

    Private Shared Sub FormatTypePropertyChanged(ByVal target As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        If CType(e.NewValue, TextBoxFormatterType) = TextBoxFormatterType.None Then
            UnregisterFormatTypeControl(target)
        Else
            RegisterFormatTypeControl(target)
        End If
    End Sub

    ' ------------------------------------------------------
    ' Define the a collection of event listerns for the
    ' FormatType "PropertyChanged" event

    Private Shared _registeredFormatTypeControlDelegates As New Dictionary(Of TextBox, RoutedEventHandler)

    ' ------------------------------------------------------
    ' Register a control as an event listener
    ' (also, attach to the control's LostFocus event)

    Private Shared Sub RegisterFormatTypeControl(ByVal candidate As DependencyObject)
        Dim l_control = TryCast(candidate, TextBox)
        If l_control IsNot Nothing Then
            Dim l_handler = New RoutedEventHandler(AddressOf FormatTypeControl_LostFocus)
            _registeredFormatTypeControlDelegates.Add(l_control, l_handler)
            l_control.AddHandler(TextBox.LostFocusEvent, l_handler)
        End If
    End Sub

    ' ------------------------------------------------------
    ' Unregister a control as an event listener
    ' (also, unattach from the control's LostFocus event)

    Private Shared Sub UnregisterFormatTypeControl(ByVal candidate As DependencyObject)
        Dim l_control = TryCast(candidate, TextBox)
        If l_control IsNot Nothing AndAlso _registeredFormatTypeControlDelegates.ContainsKey(l_control) Then
            Dim l_handler = _registeredFormatTypeControlDelegates(l_control)
            l_control.RemoveHandler(TextBox.LostFocusEvent, l_handler)
            _registeredFormatTypeControlDelegates.Remove(l_control)
        End If
    End Sub

    ' ------------------------------------------------------
    ' On the control's LostFocus event, apply the format
    ' (You could apply the format based on another event,
    ' just be careful if using the TextChanged event - it
    ' will fire whether the user has changed the text or
    ' your code has changed the text - could introduce an
    ' infinite loop)

    Private Shared Sub FormatTypeControl_LostFocus(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Dim l_textBox = TryCast(e.Source, TextBox)
        If l_textBox IsNot Nothing Then

            Dim l_formatType = CType(l_textBox.GetValue(FormatTypeProperty), TextBoxFormatterType)
            Select Case l_formatType

                Case TextBoxFormatterType.SocialSecurityNumber
                    ' Apply the format to the l_textBox
                    ' (What do you want a social security number to look like?)

                Case TextBoxFormatterType.ZipCode
                    ' Apply the format to the l_textBox
                    ' (What do you want a zip code to look like?)

                Case TextBoxFormatterType.Etc
                    ' Apply the format to the l_textBox

            End Select

        End If
    End Sub

End Class

Public Enum TextBoxFormatterType
    None
    ZipCode
    SocialSecurityNumber
    Etc
End Enum

上面看起来有点混乱,但是一旦编写了代码(一次),您就可以在 UI 中一遍又一遍地使用它:

<Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:WpfApplication1"
        Title="Window1">
  <Grid>

    <StackPanel>

      <TextBox this:TextBoxFormatter.FormatType="SocialSecurityNumber" />
      <TextBox this:TextBoxFormatter.FormatType="ZipCode" />
      <TextBox this:TextBoxFormatter.FormatType="None" />

    </StackPanel>

  </Grid>
</Window>

这种方法的一个优点是“FormatType”成为依赖属性,这意味着您可以在运行时将值绑定到它(而不是像上面的示例那样仅仅进行编码)。例如:

<TextBox this:TextBoxFormatter.FormatType="{Binding ViewModel.DesiredFormat}" />

2
投票

您可以创建一个依赖属性并在 XAML 中使用它,如下所示:

ExpandedTextBoxEvents.Subscribe="True"

依赖属性将存在于

ExpandedTextBoxEvents
类中,而 Subscribe 属性在设置为
True
时可以建立所有必要的事件订阅。

这将为您留下一个单独的类,由 XAML(或 C#,如果您愿意)通过一个简单的语句引入。


0
投票

EH 在另一个班级。我假设你的意思是 B 类在上下文中没有 A 类或其任何内部工作的概念,反之亦然。

我发现

CommunityToolkit.Mvvm
消息非常有效。注册为
IRecipient<YourMessage>
然后通过
IMessenger
发送消息非常简单。他们甚至还提供了
WeakReferenceMessenger.Default

您可能会看一下那个包裹。

奖金,还提供了不错的

RelayCommand
,以及可观察性,
ObservableObject
等支持。

HTH

© www.soinside.com 2019 - 2024. All rights reserved.