How to add blend interaction trigger to style resource(如何给通用样式添加触发命令)

50 篇文章 2 订阅

The Most improtant is that:

 <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>

 This is the detail:

So I must admit that I had a working answer when I wrote this, but it took me a long time to figure it out so I am posting it here hoping it helps someone else even though it is a very specific scenario.

I am using the MVVM model for my application so I don't want to have code behind the xaml pages. I also wanted a way to have a textbox bind to the IDataErrorInfo properties where the validation for that textbox is triggered through the lostfocus event of the textbox. This event will be bound to a relay command on the viewmodel that will validate the applicable object and add realted errors.

So i needed to have the textbox lostfocus eventcommand take the textbox name (which matches the column names from the database) as a command parameter. 

Here is a screen shot of what I am trying to accomplish

WPF Screen Shot of Textbox Validation STyle

Here is how I did it:

First I defined the command on the view model:

Imports GalaSoft.MvvmLight.Command
Private _LostFocusValidateCommand As RelayCommand(Of String)

    Public ReadOnly Property LostFocusValidateCommand() As RelayCommand(Of String)
        Get
            If _LostFocusValidateCommand Is Nothing Then
                _LostFocusValidateCommand = New RelayCommand(Of String)(AddressOf LostFocusValidateExecute)
            End If
            Return _LostFocusValidateCommand
        End Get
    End Property
    Private Sub LostFocusValidateExecute(sParam As String)
        NewClient.PropertyValitaion(False, sParam)
    End Sub

here is the property validation using IDataErrorInfo (I left out he basic implementation of IDataErrorInfo to save space, leave a comment if you want me to post it)

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

The hard part was figuring out how to define the style. The style is long, sorry, the joys of "readable" 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>

all the magic happens in the property template. THe following must be included in the top declarations of your resource dictionary:

> xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
> xmlns:cmd="http://www.galasoft.ch/mvvmlight"

 

all the magic happens in the template property that defines the control template. You can not wrap a i:interaction in the control template itself, it must be contained within a derived object, almost anything really, border, scrollviewer, wrappanel etc... Then you set the vent trigger and the command properties. They should be easy enough to follow, I pass the textbox name as the command parameter. The client "box" you see in the screen shot is a grid with its data context set to a new client object property of the parent viewmodel. SO in order to access the command in the parent viewmodel, I had to reference the parent's datacontext and call the command property.

Again, I realize that this is a very specific scenario, but I thought it has some examples that might be able to help others. I am now able to define one style for all textboxes in the application that are data-entry and that I want to trigger basic validation procedures. It will save me having to define the custom command behaviour on all those text boxes individually, and this is all accomplished in xaml, with out code behind.

Cheers

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值