2013-04-08 4 views
5

Я работаю над Windows Store App с C# и сталкивался с чем-то, где я не могу себе представить, что это сложно, но я не могу понять, как это сделать.XAML - простая анимация для простого пользовательского контроля

На моем MainPage.xaml Я создал пользовательский элемент управления: A StackPanel с горизонтальной ориентацией, всего лишь Image и TextBlock внутри. Как это:

<!-- language: lang-xml --> 
<StackPanel Width="300" Height="100" Orientation="Horizontal" Margin="0,0,0,20" Tapped="LoremIpsum_Tapped"> 
    <Image Source="/Assets/pic.jpg" Margin="20"/> 
    <TextBlock FontFamily="Segoe UI" FontSize="30" VerticalAlignment="Center"> 
     Lorem Ipsum 
    </TextBlock> 
</StackPanel> 

который выглядит следующим образом:

enter image description here

Я использую его в качестве пользовательского типа кнопки, чтобы добраться до какой-то суб-страницы. Теперь дело в том, что есть нет анимаций. Я хотел иметь типичную анимацию, которую ListItem имеет в SplitView: при нажатии она сокращается, возвращается в нормальное состояние, когда отпущена или когда указатель выходит из виртуальных границ элемента управления. Я не смог найти объявление/определение анимации, связанное с этими ListItems (Common. StandardStyles.xamlStandard130ItemTemplate). Но я узнал (here), что для этого есть предопределенные анимации: PointerDownThemeAnimation и PointerUpThemeAnimation. Но потом мне потребовалось немало времени, чтобы узнать, как применять их к контролю. Вы можете подумать, что образец, упомянутый на this site specifically about those pointer theme animations (около C#), должен помочь, но это приводит к sample for HTML/Javascript animations. Но я нашел решения here, here и here.

Так что мне нужно было Storyboard s в ресурсах управления, имя, чтобы элемент управления мог быть нацелен и обработчики событий в коде.

Наносится на моем XAML становится это:

<!-- language: lang-xml --> 
<StackPanel x:Name="LoremIpsum" Width="300" Height="100" Orientation="Horizontal" Margin="0,0,0,20" Tapped="LoremIpsum_Tapped" PointerPressed="LoremIpsum_AnimDown" PointerReleased="LoremIpsum_AnimUp" PointerExited="LoremIpsum_AnimUp"> 
    <Image Source="/Assets/pic.jpg" Margin="20"/> 
    <TextBlock FontFamily="Segoe UI" FontSize="30" VerticalAlignment="Center"> 
     Lorem Ipsum 
    </TextBlock> 
    <StackPanel.Resources> 
     <Storyboard x:Name="pointerDownStoryboard"> 
      <PointerDownThemeAnimation TargetName="LoremIpsum" /> 
     </Storyboard> 
     <Storyboard x:Name="pointerUpStoryboard"> 
      <PointerUpThemeAnimation TargetName="LoremIpsum" /> 
     </Storyboard> 
    </StackPanel.Resources> 
</StackPanel> 

плюс дополнительные обработчики событий в отделенном коде:

<!-- language: lang-cs --> 
private void Latest_AnimDown(object sender, PointerRoutedEventArgs e) 
{ 
    pointerDownStoryboard.Begin(); 
} 
private void Latest_AnimUp(object sender, PointerRoutedEventArgs e) 
{ 
    pointerUpStoryboard.Begin(); 
} 

Это работало. Но ... поскольку у меня много таких пользовательских элементов управления, я, конечно, не хочу добавлять все это для каждого элемента управления. Как упоминалось ранее, Standard130ItemTemplate не помогло. Поэтому я подумал о пользовательских элементах управления. Я надеялся, что могу просто определить MyStackPanel, это ничего, кроме StackPanel + StoryBoard s, и что нацеливание на x: Name будет работать, и, возможно, я могу поместить обработчики событий в код LayoutAwarePage, так что все остальные наследуют от Это.

Я начал искать, как это сделать, и нашел этот образец того, как создавать пользовательские элементы управления: XAML user and custom controls sample.

Там в пользовательский элемент управления в Generic.xml:

<!-- language: lang-xml --> 
xmlns:local="using:UserAndCustomControls"> 
<Style TargetType="local:BasicCustomControl"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="local:BasicCustomControl"> 
       <Border 
        Background="{TemplateBinding Background}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

И файл кода, но не код-за:

<!-- language: lang-cs --> 
namespace UserAndCustomControls 
{ 
    public sealed class BasicCustomControl : Control 
    { 
     public BasicCustomControl() 
     { 
      this.DefaultStyleKey = typeof(BasicCustomControl); 
     } 
    } 
} 

Но образец не содержал ничего об анимации. Поэтому я играл с примером, пытаясь добавить StoryBoard s к границе или к ControlTemplate, добавив обработчики событий к самостоятельно созданному коду Generic.xaml.cs. Ничего не получилось.

Затем я нашел this, но не был уверен, как и почему поставить обработчик событий в класс BasicCustomControl. Я попробовал это в любом случае:

Generic.xaml В:

<!-- language: lang-xml --> 
xmlns:local="using:UserAndCustomControls"> 
<Style TargetType="local:BasicCustomControl"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="local:BasicCustomControl"> 
       <Border x:Name="Border" 
        Background="{TemplateBinding Background}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"> 
        <Border.Resources> 
         <Storyboard x:Name="pointerDownStoryboard"> 
          <PointerDownThemeAnimation TargetName="Border" /> 
         </Storyboard> 
         <Storyboard x:Name="pointerUpStoryboard"> 
          <PointerUpThemeAnimation TargetName="Border" /> 
         </Storyboard> 
        </Border.Resources> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

И в BasicCustomControl.cs:

<!-- language: lang-cs --> 
protected override void OnPointerPressed(PointerRoutedEventArgs e) 
{ 
    ((Storyboard)this.Resources["PointerDownThemeAnimation"]).Begin(this); 
} 

Это не сработало. Метод Begin() не принимает аргументов и без аргумента, с которым была выполнена сборка, но при нажатии на элемент управления я получил сообщение System.Runtime.InteropServices.COME.

Тогда я нашел это на SO: How to add XAML storyboard animation to a full blown WPF Custom Control in an XBAP?

Это кажется интересным решением, но я не понимаю. Вот также описание VisualState для пользовательских элементов управления, но опять же я не знаю, как применить это к моим потребностям: Quickstart: control templates

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

Резюмируя вопросы:

  1. Где анимация в Standard130ItemTemplate определены и «прикрепленные» к шаблону?
  2. Есть ли элемент управления, который я могу «наследовать» от того, что ведет себя так, как я хочу (только эти анимации вверх/вниз на трех событиях)?
  3. Есть ли способ создать такой контроль, который я могу унаследовать от - с помощью кода XAML +?
  4. Есть ли способ сделать это только с помощью XAML? Это предпочтительнее прежнего?
  5. Есть ли простой пример или учебник по этому вопросу?
  6. Есть ли коллекции пользовательских элементов управления, которые я могу загрузить и использовать? Я не смог найти никого.

ответ

0

Создайте собственный стиль. В этом примере я привязал источник изображения к полю содержимого. Поэтому мне просто пришлось поместить свой путь в мой образ в этом поле (например, «Assets/Image.png»). Было бы неплохо, если бы добавление пользовательских анимаций, подобных этому, было проще выяснить в первый раз.

<Style x:Key="ImageButtonStyle" TargetType="ButtonBase"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="ButtonBase"> 
       <Grid x:Name="RootGrid" Background="Transparent"> 
        <Image x:Name="ImageLabel" Source="{TemplateBinding Content}"/> 
        <Rectangle 
          x:Name="FocusVisualWhite" 
          IsHitTestVisible="False" 
          Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}" 
          StrokeEndLineCap="Square" 
          StrokeDashArray="1,1" 
          Opacity="0" 
          StrokeDashOffset="1.5"/> 
        <Rectangle 
          x:Name="FocusVisualBlack" 
          IsHitTestVisible="False" 
          Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}" 
          StrokeEndLineCap="Square" 
          StrokeDashArray="1,1" 
          Opacity="0" 
          StrokeDashOffset="0.5"/> 

        <VisualStateManager.VisualStateGroups> 
         <VisualStateGroup x:Name="CommonStates"> 
          <VisualState x:Name="Normal"/> 
          <VisualState x:Name="PointerOver"> 
          </VisualState> 
          <VisualState x:Name="Pressed"> 
           <Storyboard> 
            <PointerDownThemeAnimation TargetName="ImageLabel" /> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="Disabled"> 
          </VisualState> 
         </VisualStateGroup> 
         <VisualStateGroup x:Name="FocusStates"> 
          <VisualState x:Name="Focused"> 
           <Storyboard> 
            <DoubleAnimation 
              Storyboard.TargetName="FocusVisualWhite" 
              Storyboard.TargetProperty="Opacity" 
              To="1" 
              Duration="0"/> 
            <DoubleAnimation 
              Storyboard.TargetName="FocusVisualBlack" 
              Storyboard.TargetProperty="Opacity" 
              To="1" 
              Duration="0"/> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="Unfocused" /> 
          <VisualState x:Name="PointerFocused" /> 
         </VisualStateGroup> 
         <VisualStateGroup x:Name="CheckStates"> 
          <VisualState x:Name="Checked"> 
           <Storyboard> 
            <DoubleAnimation Duration="0" To="0" Storyboard.TargetName="OutlineGlyph" Storyboard.TargetProperty="Opacity"/> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGlyph" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource AppBarItemForegroundThemeBrush}"/> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundCheckedGlyph" Storyboard.TargetProperty="Visibility"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> 
            </ObjectAnimationUsingKeyFrames> 
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground"> 
             <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource AppBarItemPressedForegroundThemeBrush}"/> 
            </ObjectAnimationUsingKeyFrames> 
           </Storyboard> 
          </VisualState> 
          <VisualState x:Name="Unchecked"/> 
          <VisualState x:Name="Indeterminate"/> 
         </VisualStateGroup> 
        </VisualStateManager.VisualStateGroups> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
Смежные вопросы