Silverlight: Может ли событие из одного usercontrol запускать анимацию на другом usercontrol и / или содержащем элементе управления

#c# #wpf #silverlight #xaml #visualstatemanager

#c# #wpf #silverlight #xaml #visualstatemanager

Вопрос:

У меня есть три пользовательских элемента управления в Silverlight.

UCOutside содержит два пользовательских элемента управления, называемых UCInside1 и UCInside2.

Содержащем пользовательский элемент управления

 <!-- UCOutside --> 
<UserControl.Resources>
    <Storyboard x:Name="OutsideBoard">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="LayoutRoot">
            <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="45"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</UserControl.Resources>

<Grid x:Name="LayoutRoot">
    <Grid.Projection>
        <PlaneProjection/>
    </Grid.Projection>
    <local:UCInside1 Margin="39,35,266,173"/>
    <local:UCInside2 HorizontalAlignment="Right" Margin="0,234,26,30" />
</Grid>
  

Первый пользовательский элемент управления внутри

 <!-- UCInside1 -->
<UserControl.Resources>
    <Storyboard x:Name="ImageFade">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="myImage">
            <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0.2"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image x:Name="myImage" Margin="0" Source="/OtherImage.png" Stretch="Fill" Width="312" Height="250" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
  

Второй пользовательский элемент управления внутри

 <!-- UCInside2 -->
<UserControl.Resources>
    <Storyboard x:Name="ButtonFade">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="image1">
            <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>
            <EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" HorizontalAlignment="Left" Height="195" VerticalAlignment="Top" Width="218">
    <Button Content="Button" HorizontalAlignment="Right" Margin="0,0,25,51" VerticalAlignment="Bottom" Width="75" Click="ClickButton"/>
    <Image x:Name="image1" HorizontalAlignment="Left" Margin="41,32,0,70" Source="/Whatever.png" Stretch="Fill" Width="47"/>
</Grid>
  

Вы заметите, что событие ClickButton на кнопке. Вы также заметите, что во всех пользовательских элементах управления указаны простые раскадровки.

Вопрос в том, как мне запустить все три анимации с помощью события Click? Можно ли все это связать с помощью XAML или с помощью Blend? Если нет, то как это делается в коде c #?

Ответ №1:

я бы сказал, что очень простым и эффективным способом решения этой проблемы было бы использовать интерфейс INotifyPropertyChanged для использования шаблона Observer.

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

Как только ваш класс OutsideContainer станет наблюдаемым, выполните эти два шага:

  1. В классе OutsideButton запускает событие PropertyChanged в соответствующем месте (например, там, где происходит «супер» щелчок.

  2. В классах ImageFade и ButtonFace зафиксируйте событие PropertyChanged и сделайте что-нибудь (например, позвольте им запускать свое собственное событие click-event).

Попробуйте следующее:

В коде OutsideBoard.cs реализовать интерфейс INotifyPropertyChanged, чтобы сделать его наблюдаемым:

 class OutsideBoard : INotifyPropertyChanged {

    public event PropertyChangedEventHandler PropertyChanged;

    private void FirePropertyChanged (string property) {

        if (PropertyChanged != null) {

            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    // the click- EventHandler of your UserControl
    public event Click_EventHandler (object sender, RoutedEventArgs e) {

        // your clicking code of your UserControl

        FirePropertyChanged("SuperClick");
    }


    // rest of the code inhere ...
}
  

Теперь каждый класс, который хочет наблюдать за классом OutsideBorder, должен реализовать обработчик событий в этом классе:

Напишите что-то вроде следующего в вашем классе ButtonFade и ImageFade:

 outsideBorder.PropertyChanged  = PropertyEventChangeHandler(MyClickHandling);

public void MyClickHandling (object sender, PropertyChangeEventArgs e) {

     // do something
}
  

Таким образом, всякий раз, когда класс OutsideBoard запускает событие PropertyChanged , все наблюдатели получат уведомление, вызвав свой MyClickHandling — метод.

Надеюсь, это вам поможет.

Комментарии:

1. Марк, спасибо. Использование INotifyPropertyChanged — это способ сделать это, но не совсем так, как вы показали выше. Что я сделал, так это заставил дочерний элемент управления (то есть тот, который фактически содержит кнопку и впоследствии получает ее событие) реализовать интерфейс INotifyPropertyChanged. Когда это делается, все, что должен сделать содержащий пользовательский элемент управления, это подписаться на событие PropertyChanged, и если другой дочерний элемент управления также должен быть уведомлен, то этот другой дочерний элемент управления может реализовать и предоставить обработчик для PropertyChanged, а содержащий UserControl может подписаться на другого дочернего элемента на событие.

Ответ №2:

Пройдя через это снова, я понял, что может быть гораздо более простое решение 🙂

Если вы хотите отреагировать в своем классе OutsideBoard на событие щелчка другого класса — просто перехватите это конкретное событие 🙂

итак, в коде за вашими «дочерними элементами» просто напишите (предполагая, что ваш класс OutsideBorder является outsideBorder:

 outsideBorder.Click  = MouseEventHandler(MyClickHandler);

public void MyClickHandler (object sender, MouseEventArgs e) {

    // do something to react on the click appeared in the OutsideBoard class.
}
  

Таким образом, событие щелчка на внешней панели будет обрабатываться как само по себе (без вашего вмешательства) Что вы делаете, так это просто добавляете дополнительный обработчик событий к этому элементу управления щелчком мыши 🙂

Комментарии:

1. Я думаю, чего я пытался избежать, так это того, что дочерние элементы знали о данных родителя. Событие происходит в дочернем элементе, но я пытаюсь выяснить, как подключить его, чтобы уведомить родительский элемент управления и уведомить другой пользовательский элемент управления, который является «родственным» из-за отсутствия лучшего термина.