내가 이것을 작성할 때 나는 작동 대답을 가지고 있음을 인정해야한다. 그러나 나는 그것을 알아 내기 위해 오랜 시간이 걸렸다. 그래서 매우 특정한 시나리오 임에도 불구하고 그것이 다른 누군가를 돕기를 바란다.
내 응용 프로그램에 MVVM 모델을 사용하고 있으므로 xaml 페이지 뒤에 코드를 넣고 싶지는 않습니다. 또한 해당 텍스트 상자에 대한 유효성 검사가 텍스트 상자의 lostfocus 이벤트를 통해 트리거되는 IDataErrorInfo 속성에 텍스트 상자를 바인딩하는 방법을 원했습니다. 이 이벤트는 viewmodel의 릴레이 명령에 바인딩되어 해당 개체의 유효성을 검사하고 실수로 발생한 오류를 추가합니다.
그래서 텍스트 상자 lostfocus eventcommand가 명령 매개 변수로 텍스트 상자 이름 (데이터베이스의 열 이름과 일치)을 가져와야했습니다.
Public Sub PropertyValitaion(bAllProperties As Boolean, Optional sProperty As String = "")
'initialize validation helper
Dim vhelper As New ValidationHelper
If bAllProperties Or sProperty = "chrCompany" Then
If String.IsNullOrEmpty(chrCompany) Then
AddError("chrCompany", "You must enter a Company Name")
Else
RemoveError("chrCompany")
End If
End If
If bAllProperties Or sProperty = "chrFirst" Then
If String.IsNullOrEmpty(chrFirst) Then
AddError("chrFirst", "You must enter a First Name")
Else
RemoveError("chrFirst")
End If
End If
If bAllProperties Or (sProperty = "chrPhone1" Or sProperty = "chrPhone1Ext") Then
If String.IsNullOrEmpty(Trim(chrPhone1Ext)) = False And String.IsNullOrEmpty(Trim(chrPhone1)) Then
Me.AddError("chrPhone1", "Provide a phone number or remove extension")
Else
RemoveError("chrPhone1")
End If
If String.IsNullOrEmpty(Trim(chrPhone1)) = False Then
If vhelper.CheckPhoneNumber(Me.chrPhone1) = False Then
Me.AddError("chrPhone1", "Phone 1 format invalid")
Else
RemoveError("chrPhone1")
End If
End If
End If
End Sub
어려운 부분은 스타일을 정의하는 방법을 알아내는 것이 었습니다. 스타일이 긴, 죄송합니다 "읽기"XML의 기쁨 :
<Style x:Key="FTC_ValidateTextBox" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
<Style.Setters>
<Setter Property="FontFamily" Value="Open Sans Condensed"/>
<Setter Property="FontSize" Value="19" />
<Setter Property="Margin" Value="3,3,15,6"/>
<Setter Property="Padding" Value="10,3"/>
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Background" Value="{StaticResource DetailTextBox}" />
<Setter Property="BorderBrush" Value="{StaticResource MediumGray}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border Name="Bd" SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<cmd:EventToCommand Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.LostFocusValidateCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}},Path=Name}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="{StaticResource MediumRed}" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<AdornedElementPlaceholder Name="parentTextBox" />
<TextBlock Grid.Row="1" Style="{StaticResource FTC_DetailError}"
Text="{Binding ElementName=parentTextBox, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
<Setter Property="BorderBrush" Value="{StaticResource MediumRed}"/>
<Setter Property="Foreground" Value="{StaticResource MediumRed}"/>
<Setter Property="Margin" Value="3,3,15,31"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="FTC_DetailError" TargetType="TextBlock">
<Style.Setters>
<Setter Property="FontFamily" Value="Open Sans Condensed"/>
<Setter Property="Control.FontWeight" Value="Light" />
<Setter Property="Foreground" Value="{StaticResource TitleWhite}"/>
<Setter Property="FontSize" Value="15" />
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="10,3"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Background" Value="{StaticResource MediumRed}"/>
</Style.Setters>
</Style>
모든 마법 속성 템플릿에 발생합니다.다음은 리소스 사전의 정상 선언에 포함되어야합니다 :
> xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
> xmlns:cmd="http://www.galasoft.ch/mvvmlight"
모든 마법이 컨트롤 템플릿을 정의하는 템플릿 속성에 발생합니다. 컨트롤 템플릿 자체에서 i : interaction을 래핑 할 수는 없으며 파생 된 객체, 거의 모든 것, 테두리, 스크롤 뷰어, wrappanel 등에 포함되어야합니다. 그런 다음 배출 트리거와 명령 속성을 설정합니다. 그들은 따라야 할만큼 쉬워야하며, 나는 명령 매개 변수로서 텍스트 박스 이름을 전달한다. 스크린 샷에서 볼 수있는 클라이언트 "박스"는 데이터 컨텍스트가 상위 뷰 모델의 새 클라이언트 객체 속성으로 설정된 그리드입니다. 그래서 부모 viewmodel에서 명령에 액세스하려면 부모의 datacontext를 참조하고 명령 속성을 호출해야했습니다.
이 시나리오는 매우 구체적인 시나리오이지만, 다른 사람들을 도울 수있는 몇 가지 예가 있다고 생각합니다. 이제 응용 프로그램에서 데이터 입력이고 모든 유효성 검사 절차를 트리거하려는 모든 텍스트 상자에 대해 하나의 스타일을 정의 할 수 있습니다. 모든 텍스트 상자에 대해 사용자 지정 명령 동작을 개별적으로 정의해야하는 번거 로움을 덜어줍니다.이 모든 작업은 xaml에서 완료되었으며, 코드가 뒤에 있습니다.
건배