我为一些自定义WPF控件构建了一系列事件处理程序。当用户根据所包含的数据类型(电话号码,邮政编码,货币价值等)输入或离开文本框时,事件处理格式化显示的文本
现在我将C#代码中的所有事件直接附加到xaml。因为我已经开发了一个可控制,这意味着逻辑重复了很多,如果我想改变程序范围的功能,我将不得不在事件代码所在的任何地方进行更改。
我确信有一种方法可以将我的所有事件处理程序放在一个类中。谁能帮我指点正确的方向?
我看到这篇文章:Event Handler located in different class than 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);
}
但那不那么优雅。
答案 0 :(得分:2)
您可以创建依赖项属性并在XAML中使用它,如下所示:
ExpandedTextBoxEvents.Subscribe="True"
依赖项属性将存在于ExpandedTextBoxEvents
类中,并且Subscribe属性可以在设置为True
时建立所有必需的事件订阅。
这将为您留下一个单独的类,在一个简单的语句中由XAML(或C#,如果您愿意)引入。
答案 1 :(得分:2)
Attached Properties是您想要的一种方法。我经常使用它们。
附加财产代码:
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}" />