WPF Как добавить триггер взаимодействия смешивания в ресурс стиля

Я использую VS 2012, с WPF 4.5

Я хочу иметь возможность добавить триггер взаимодействия смешивания к ресурсу стиля, чтобы я мог определить его в одном месте (словарь ресурсов) и использовать во многих местах моего приложения.

В частности, я хочу использовать EventToCommand, который поставляется с платформой MVVM-Light и вставлен в стиль текстового поля и присоединен к событию LostFocus текстового поля. Я планирую использовать это, чтобы пометить определенные текстовые поля с помощью ValidationStyle, который запускает связанную команду (в модели представления) для события LostFocus текстового поля. Этот стиль проверки будет использовать IDataErrorInfo для отображения ошибок пользователю через пользовательский интерфейс.

Этот вопрос похож на следующие вопросы (но они не имеют полного решения):

EventToCommand в стиле кнопки

Как добавить Blend Behavior в Style Setter

ВОПРОС: Как добавить смешанный EventToCommand в текстовое поле lostfocus, которое привязано к команде в текстовом тексте viewmodel (я не хочу использовать код позади или присоединенное свойство, я хочу, чтобы он был полностью определен в XAML)?

1 ответ

Решение

Поэтому я должен признать, что у меня был рабочий ответ, когда я писал это, но мне потребовалось много времени, чтобы понять это, поэтому я публикую это здесь, надеясь, что это поможет кому-то еще, даже если это очень специфический сценарий.

Я использую модель MVVM для своего приложения, поэтому я не хочу иметь код за страницами xaml. Я также хотел получить способ привязки текстового поля к свойствам IDataErrorInfo, где проверка этого текстового поля запускается через событие lostfocus текстового поля. Это событие будет связано с командой ретрансляции на модели представления, которая проверит применимый объект и добавит обнаруженные ошибки.

Поэтому мне нужно было, чтобы текстовое поле lostfocus eventcommand принимало имя текстового поля (совпадающее с именами столбцов из базы данных) в качестве параметра команды.

Вот скриншот того, что я пытаюсь сделатьСнимок экрана WPF стиля проверки текстового поля

Вот как я это сделал:

Сначала я определил команду для модели представления:

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

Вот проверка свойства с использованием IDataErrorInfo (я оставил базовую реализацию IDataErrorInfo для экономии места, оставьте комментарий, если хотите, чтобы я его опубликовал)

 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"

вся магия происходит в свойстве шаблона, которое определяет шаблон элемента управления. Вы не можете обернуть ai: взаимодействие в сам шаблон элемента управления, оно должно содержаться в производном объекте, почти что-нибудь на самом деле, border, scrollviewer, wrappanel и т. Д. Затем вы устанавливаете триггер вентиляции и свойства команды. За ними должно быть достаточно легко следить, я передаю имя текстового поля в качестве параметра команды. "Окно" клиента, которое вы видите на снимке экрана, является сеткой, контекст контекста данных которой установлен на новое свойство объекта клиента родительской модели представления. Итак, чтобы получить доступ к команде в родительской модели представления, мне пришлось обратиться к родительскому текстовому тексту и вызвать свойство команды.

Опять же, я понимаю, что это очень специфический сценарий, но я подумал, что у него есть некоторые примеры, которые могут помочь другим. Теперь я могу определить один стиль для всех текстовых полей в приложении, которые являются вводом данных и которые я хочу запустить основные процедуры проверки. Это избавит меня от необходимости определять индивидуальное поведение команды для всех этих текстовых полей по отдельности, и все это выполняется в xaml без кода.

ура

Другие вопросы по тегам