2

現在、Silverlight でいくつかのカスタム コントロールを構築しています。これらのコントロールが検証エラーに応答するようにします。私がやろうとしているのは、デフォルトの Silverlight コントロールと同じように、コントロールの周りに赤い境界線を引くことです。

私が理解しているのは、これをテンプレートに追加する必要があるということです:

<VisualStateManager.VisualStateGroups>
  <VisualStateGroup x:Name="ValidationStates">
    <VisualState x:Name="Valid"/>
    <VisualState x:Name="InvalidUnfocused">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </VisualState>
    <VisualState x:Name="InvalidFocused">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <Visibility>Visible</Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <sys:Boolean>True</sys:Boolean>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </VisualState>
  </VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ValidationErrorElement" BorderThickness="1" CornerRadius="1" BorderBrush="#FFDB000C" Visibility="Collapsed">
  <ToolTipService.ToolTip>
    <ToolTip x:Name="validationTooltip" Template="{StaticResource ValidationToolTipTemplate}" Placement="Right"
              PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
              DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
      <ToolTip.Triggers>
        <EventTrigger RoutedEvent="Canvas.Loaded">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
                  <DiscreteObjectKeyFrame KeyTime="0">
                    <DiscreteObjectKeyFrame.Value>
                      <sys:Boolean>true</sys:Boolean>
                    </DiscreteObjectKeyFrame.Value>
                  </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>
      </ToolTip.Triggers>
    </ToolTip>
  </ToolTipService.ToolTip>
  <Grid Width="12" Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Background="Transparent">
    <Path Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C"/>
    <Path Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff"/>
  </Grid>
</Border>

<ControlTemplate x:Key="ValidationToolTipTemplate">
  <Grid x:Name="Root" Margin="5,0" RenderTransformOrigin="0,0" Opacity="0">
    <Grid.RenderTransform>
      <TranslateTransform x:Name="xform" X="-25"/>
    </Grid.RenderTransform>
    <VisualStateManager.VisualStateGroups>
      <VisualStateGroup Name="OpenStates">
        <VisualStateGroup.Transitions>
          <VisualTransition GeneratedDuration="0"/>
          <VisualTransition To="Open" GeneratedDuration="0:0:0.2">
            <Storyboard>
              <DoubleAnimation Storyboard.TargetName="xform" Storyboard.TargetProperty="X" To="0" Duration="0:0:0.2">
                <DoubleAnimation.EasingFunction>
                  <BackEase Amplitude=".3" EasingMode="EaseOut"/>
                </DoubleAnimation.EasingFunction>
              </DoubleAnimation>
              <DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.2"/>
            </Storyboard>
          </VisualTransition>
        </VisualStateGroup.Transitions>
        <VisualState x:Name="Closed">
          <Storyboard>
            <DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
          </Storyboard>
        </VisualState>
        <VisualState x:Name="Open">
          <Storyboard>
            <DoubleAnimation Storyboard.TargetName="xform" Storyboard.TargetProperty="X" To="0" Duration="0"/>
            <DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
          </Storyboard>
        </VisualState>
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Border Margin="4,4,-4,-4" Background="#052A2E31" CornerRadius="5"/>
    <Border Margin="3,3,-3,-3" Background="#152A2E31" CornerRadius="4"/>
    <Border Margin="2,2,-2,-2" Background="#252A2E31" CornerRadius="3"/>
    <Border Margin="1,1,-1,-1" Background="#352A2E31" CornerRadius="2"/>

    <Border Background="#FFDC000C" CornerRadius="2"/>
    <Border CornerRadius="2">
      <TextBlock
          UseLayoutRounding="false"
          Foreground="White" Margin="8,4,8,4" MaxWidth="250" TextWrapping="Wrap" Text="{Binding (Validation.Errors)[0].ErrorContent}"/>
    </Border>
  </Grid>
</ControlTemplate>

そして、作成するすべてのコントロールにこれを追加する必要があります (ValidationToolTipTemplate-ControlTemplate を除く)。

  1. すべてのコントロールに検証スタイルを追加し、DRY のままにするにはどうすればよいですか?
  2. それが不可能な場合、検証テンプレートのスタイルが変更された場合、既知のユニバースのすべてのコントロールのテンプレートをコピーして「generic.xaml」というファイルに貼り付け、それに応じて変更する必要があるということですか?

(2) がおそらく進むべき道であることを知るのに十分長い間 Microsoft API を使用してきましたが、最初に確認したいと思います。

4

1 に答える 1

3

Silveright/WPF の動作方法には、この種の状況でいくつかの落とし穴があります。ControlTemplatesはすべてまたは何もないため、XAML を繰り返すことになります。スタイルのテンプレートを置き換えるか、置き換えないかのどちらかです。クラスの場合のように、何をオーバーライドするかを選択することはできません。

具体的な質問に答えてから、XAML ファイルの冗長性を排除するのに役立ついくつかの広範なアプローチを提供しようとします。

すべてのコントロールに検証スタイルを追加するにはどうすればよいですか?

まず、その境界線を取得し、Key 属性を指定して StaticResoruce にします。次に、共有リソース ディクショナリに配置します。スタイルが再度必要になった場合は、次のようにテンプレートで使用できます。

<ContentControl x:Name="ValidationErrorElement" Content={StaticResource MyBorderResource}" />

テンプレートをカプセル化するために、それ以上のことはできません。Validation VisualStates に関する限り、これらは既に可能な限りコンパクトになっています。ただし、できることは、複数のテンプレートを 1 つの大きなテンプレートに結合することです。ボタンのように見える ToggleButtons、Buttons、RadioButtons でこれを行うのが好きです。以下のポイント 2 を参照してください。

一般的な経験則

  1. 一般的に使用される XAML フラグメントを、テンプレート化されたコントロールとコントロール テンプレートにカプセル化します。たとえば、いくつかの異なる場所で使用している境界線内に境界線があるとしましょう。これは、ControlTemplate リソースとして記述され、ContentControl に読み込まれます。

  2. ほとんど同じ (Button、ToggleButton、RadioButton など) のスタイルまたはコントロール テンプレートがいくつかある場合は、この場合、共通の祖先ButtonBaseにスタイルを適用できます。新しいボタン ControlTemplate には、Button、ToggleButton、RadioButton に必要なすべての VisualStates とグラフィック要素が含まれ、ButtonBase 型に適用されます。前述のように、このアプローチは非常によく似た外観のコントロールには適していますが、それほど似ていないコントロールには適していません。

于 2012-07-25T19:49:39.220 に答える