WPF

2013-02-20 9 views
1

난 내가 하나에 정의 된 것을 가질 수 있도록 스타일 리소스에 혼합 상호 작용 트리거를 추가 할 수 있도록 WPF 4.5WPF

와 VS 2012를 사용하고 있습니다 장소 (리소스 사전) 및 내 애플 리케이션을 통해 여러 곳에서 사용합니다.

특히 MVVM-Light 프레임 워크와 함께 제공되고 텍스트 상자 스타일에 삽입되고 텍스트 상자의 LostFocus 이벤트에 첨부되는 EventToCommand를 사용하려고합니다. 나는 특정 텍스트 박스에 ValidationStyle으로 표시하여 (뷰 모델에서) 텍스트 상자의 LostFocus 이벤트에 대한 바운드 명령을 트리거하도록 계획하고 있습니다. 이 유효성 검사 스타일은 IDataErrorInfo를 사용하여 UI를 통해 사용자에게 오류를 표시합니다.

이 질문에 (하지만 그들은 전체 솔루션이없는) 다음 질문에 유사합니다

EventToCommand in button style

How to add a Blend Behavior in a Style Setter

는 질문 : 가 어떻게에 혼합 EventToCommand을 추가 할 수 있습니다 viewmodel datacontext의 명령에 바인딩 된 텍스트 상자 lostfocus (코드를 사용하거나 첨부 된 속성을 사용하고 싶지 않습니다. XAML에서 완전히 정의되기를 원합니다)?

답변

2

내가 이것을 작성할 때 나는 작동 대답을 가지고 있음을 인정해야한다. 그러나 나는 그것을 알아 내기 위해 오랜 시간이 걸렸다. 그래서 매우 특정한 시나리오 임에도 불구하고 그것이 다른 누군가를 돕기를 바란다.

내 응용 프로그램에 MVVM 모델을 사용하고 있으므로 xaml 페이지 뒤에 코드를 넣고 싶지는 않습니다. 또한 해당 텍스트 상자에 대한 유효성 검사가 텍스트 상자의 lostfocus 이벤트를 통해 트리거되는 IDataErrorInfo 속성에 텍스트 상자를 바인딩하는 방법을 원했습니다. 이 이벤트는 viewmodel의 릴레이 명령에 바인딩되어 해당 개체의 유효성을 검사하고 실수로 발생한 오류를 추가합니다.

그래서 텍스트 상자 lostfocus eventcommand가 명령 매개 변수로 텍스트 상자 이름 (데이터베이스의 열 이름과 일치)을 가져와야했습니다.

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 
:

먼저 내가보기 모델에 명령을 정의 : 여기

내가 여기 WPF Screen Shot of Textbox Validation STyle

달성하기 위해 노력하고 있습니다 무엇의 스크린 샷 내가 그것을 어떻게입니다

여기 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" 

모든 마법이 컨트롤 템플릿을 정의하는 템플릿 속성에 발생합니다. 컨트롤 템플릿 자체에서 i : interaction을 래핑 할 수는 없으며 파생 된 객체, 거의 모든 것, 테두리, 스크롤 뷰어, wrappanel 등에 포함되어야합니다. 그런 다음 배출 트리거와 명령 속성을 설정합니다. 그들은 따라야 할만큼 쉬워야하며, 나는 명령 매개 변수로서 텍스트 박스 이름을 전달한다. 스크린 샷에서 볼 수있는 클라이언트 "박스"는 데이터 컨텍스트가 상위 뷰 모델의 새 클라이언트 객체 속성으로 설정된 그리드입니다. 그래서 부모 viewmodel에서 명령에 액세스하려면 부모의 datacontext를 참조하고 명령 속성을 호출해야했습니다.

이 시나리오는 매우 구체적인 시나리오이지만, 다른 사람들을 도울 수있는 몇 가지 예가 있다고 생각합니다. 이제 응용 프로그램에서 데이터 입력이고 모든 유효성 검사 절차를 트리거하려는 모든 텍스트 상자에 대해 하나의 스타일을 정의 할 수 있습니다. 모든 텍스트 상자에 대해 사용자 지정 명령 동작을 개별적으로 정의해야하는 번거 로움을 덜어줍니다.이 모든 작업은 xaml에서 완료되었으며, 코드가 뒤에 있습니다.

건배