2009-09-22 21 views
5

Próbuję wykonać niestandardową kontrolę w WPF. Chcę, aby symulował zachowanie diody LED, która może migać.Jak zrobić miganie elipsy?

Sterowanie odbywa się w trzech stanach: Włączony, Wyłączony i Migający.

Wiem, jak ustawić On i Off za pomocą kodu, ale to animacja WPF tylko doprowadza mnie do szału !!!! Nie mogę niczego wskrzesić. Plan zakłada posiadanie właściwości zwanej stanem. Gdy użytkownik ustawia wartość migania, chcę, aby kontrolka zmieniała się na zielono i szaro. Zakładam, że potrzebuję tutaj właściwości zależności, ale nie mam pojęcia. Miałem więcej xaml przed, ale po prostu wymazałem to wszystko. wydaje się, że nic nie robi. Chciałbym zrobić to w jak najlepszy możliwy sposób, ale w tym momencie wezmę wszystko. Jestem w połowie drogi do napisania wątku, który zmienia kolor ręcznie w tym momencie.

<UserControl x:Class="WpfAnimation.LED" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Height="300" Width="300"> 

<Grid> 
    <Ellipse x:Name="MyLight" Height="Auto" Width="Auto"/> 
</Grid> 

</UserControl> 
+0

Zakładam, że próbujesz wykonać animację w Visual Studio - użyj do tego funkcji Expression Blend - ma ona narzędzie do projektowania animacji. –

+0

Jestem. Przyznam, że po tym, jak spędziłem trochę czasu, nigdzie nie dotarłem i nie dotrzymałem terminu, zacząłem się trochę denerwować i trochę straciłem głowę. Uruchomiłem Expression Blend i zobaczyłem, że utworzony przez ciebie storyboard działa dobrze. Potrzebowałem tylko drobnych korekt, aby uzyskać pożądane zachowanie. – MedicineMan

+0

Czy można to zrobić za pomocą czegoś takiego jak zegar lub oddzwanianie, z dwoma elipsami, których widoczność zmienia się na przemian? Ale ja też lubię odpowiedź Pax. :) –

Odpowiedz

7

Można to zrobić z animacją, że auto-odwraca i powtarza (jest to dla Silverlight):

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="Blinker.MainPage" 
    Width="640" Height="480" Loaded="UserControl_Loaded"> 
    <UserControl.Resources> 
     <Storyboard x:Name="Blink" AutoReverse="True" RepeatBehavior="Forever"> 
      <ColorAnimationUsingKeyFrames BeginTime="00:00:00" 
       Storyboard.TargetName="ellipse" 
       Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"> 
       <EasingColorKeyFrame KeyTime="00:00:01" Value="Gray"/> 
      </ColorAnimationUsingKeyFrames> 
     </Storyboard> 
    </UserControl.Resources> 
    <Grid x:Name="LayoutRoot" Background="White"> 
     <Ellipse x:Name="ellipse" Fill="Green" Stroke="Black"/> 
    </Grid> 
</UserControl> 

a następnie uruchomić animację podczas ładowania kontroli lub gdy właściwość jest ustawiona - nie trzeba właściwość zależność chyba

private bool blinking; 
public bool IsBlinking 
{ 
    get 
    { 
     return blinking; 
    } 
    set 
    { 
     if (value) 
     { 
      this.Blink.Begin(); 
     } 
     else 
     { 
      this.Blink.Stop(); 
     } 

     this.blinking = value; 
    } 
} 

lub na starcie:

private void UserControl_Loaded(object sender, System.Windows.RoutedEventArgs e) 
{ 
    this.Blink.Begin(); 
} 

Oto kolejny sposób to zrobić w WPF - używając VisualStateManager - że będzie również działać w Silverlight:

<UserControl 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d" 
x:Class="BlinkerApp.Blinker" 
x:Name="UserControl" 
d:DesignWidth="100" d:DesignHeight="100"> 
<Grid x:Name="LayoutRoot"> 
    <VisualStateManager.VisualStateGroups> 
     <VisualStateGroup x:Name="BlinkStates"> 
      <VisualState x:Name="Blinking"> 
       <Storyboard AutoReverse="True" RepeatBehavior="Forever"> 
        <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"> 
         <SplineColorKeyFrame KeyTime="00:00:01" Value="Gray"/> 
        </ColorAnimationUsingKeyFrames> 
       </Storyboard> 
      </VisualState> 
      <VisualState x:Name="Stopped"/> 
     </VisualStateGroup> 
    </VisualStateManager.VisualStateGroups> 
    <Ellipse x:Name="ellipse" Fill="Green" Stroke="Black"/> 
</Grid> 

a następnie mają właściwość IsBlinking przełączyć stan wizualny:

namespace BlinkerApp 
{ 
    using System.Windows; 
    using System.Windows.Controls; 

/// <summary> 
/// Interaction logic for Blinker.xaml 
/// </summary> 
public partial class Blinker : UserControl 
{ 
    private bool blinking; 

    public Blinker() 
    { 
     this.InitializeComponent(); 
    } 

    public bool IsBlinking 
    {  
     get  
     {  
      return blinking;  
     }  

     set  
     {   
      if (value)   
      { 
       VisualStateManager.GoToState(this, "Blinking", true); 
      }   
      else   
      { 
       VisualStateManager.GoToState(this, "Stopped", true); 
      }   

      this.blinking = value;  
     } 
    }  
} 
} 
+1

Nie widzę EasingColorKeyFrame. Czy to jest rozwiązanie Silverlight? Również this.Blink.Begin() nie jest dla mnie dostępna. Używam WPF. – MedicineMan

+0

To jest rozwiązanie Silverlight. Dodam kolejną odpowiedź dla WPF. –

+0

Zastanawiam się, jak migać jednocześnie kilkoma przyciskami, nawet jeśli niektóre przyciski będą migać później? Obecnie używam timera w kodzie za: bool flashNow = teraz.Second% 2 == 0; Czy istnieje jakieś inne rozwiązanie (w XAML)? –

4

Aby umożliwić większą kontrolę szybkości migania i tym podobnych w twoim kodzie, sugerowałbym posiadanie zdarzenia routowanego w twoim UserControl o nazwie Blink:

public static readonly RoutedEvent BlinkEvent = EventManager.RegisterRoutedEvent("Blink", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(LedControl)); 
public event RoutedEventHandler Blink 
{ 
    add { AddHandler(BlinkEvent, value); } 
    remove { RemoveHandler(BlinkEvent, value); } 
} 

W kodzie tyłu można skonfigurować timer podnieść zdarzenie jednak często chcesz (w tym także daje możliwość migać świetle jeden raz, kiedy tylko chcesz Ty:

RaiseEvent(new RoutedEventArgs(LedControl.Blink)); 

teraz w XAML następujący kod spowodowałby, że blask byłby widoczny, i ustaw właściwości wypełnienia elipsy (ledEllipse) na jasnozielony gradient radialny, a następnie przywróci wartość wypełnienia do ciemniejszego "nieoświetlonego" zielonego (który można zmienić na szary, jeśli lubisz). Możesz po prostu zmienić czas trwania, aby błyskać dłużej.

<UserControl.Triggers> 
    <EventTrigger RoutedEvent="local:LedControl.Blink"> 
     <EventTrigger.Actions> 
      <BeginStoryboard> 
       <Storyboard> 
        <DoubleAnimation Storyboard.TargetName="glow" 
            Storyboard.TargetProperty="Opacity" 
            To="100" 
            AutoReverse="True" 
            Duration="0:0:0.075" /> 
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ledEllipse" 
                Storyboard.TargetProperty="Fill" 
                Duration="0:0:0.15"> 
         <ObjectAnimationUsingKeyFrames.KeyFrames> 
          <DiscreteObjectKeyFrame KeyTime="0:0:0.01"> 
           <DiscreteObjectKeyFrame.Value> 
            <RadialGradientBrush> 
             <!--bright Green Brush--> 
             <GradientStop Color="#FF215416" Offset="1"/> 
             <GradientStop Color="#FE38DA2E" Offset="0"/> 
             <GradientStop Color="#FE81FF79" Offset="0.688"/> 
            </RadialGradientBrush> 
           </DiscreteObjectKeyFrame.Value> 
          </DiscreteObjectKeyFrame> 
          <DiscreteObjectKeyFrame KeyTime="0:0:0.15" > 
           <DiscreteObjectKeyFrame.Value> 
            <RadialGradientBrush> 
             <!--dim Green Brush--> 
             <GradientStop Color="#FF21471A" Offset="1"/> 
             <GradientStop Color="#FF33802F" Offset="0"/> 
             <GradientStop Color="#FF35932F" Offset="0.688"/> 
            </RadialGradientBrush> 
           </DiscreteObjectKeyFrame.Value> 
          </DiscreteObjectKeyFrame> 
         </ObjectAnimationUsingKeyFrames.KeyFrames> 
        </ObjectAnimationUsingKeyFrames> 
       </Storyboard> 
      </BeginStoryboard> 
     </EventTrigger.Actions> 
    </EventTrigger> 
</UserControl.Triggers> 

Również jestem bezpośrednio przedstawieniu elipsę „ledEllipse” i to odpowiada DropShadowEffect „blask”, które są zdefiniowane w ledControl następująco (Redlight jest tylko kolejnym promieniowy szczotka gradientu że zacznę moją własność wypełnienia LED at) :

<Ellipse x:Name="statusLight" Height="16" Width="16" Margin="0" Fill="{DynamicResource redLight}" > 
    <Ellipse.Effect> 
     <DropShadowEffect x:Name="glow" ShadowDepth="0" Color="Lime" BlurRadius="10" Opacity="0" /> 
    </Ellipse.Effect> 
</Ellipse> 

Uwaga: DropShadowEffect został wprowadzony w .NET 3.5, ale można usunąć, że jeśli nie chce efekt poświaty (ale ładnie wygląda na jednolitym tle kontrastowym kolorze).

+0

+1 za bycie na miejscu z kolorami. Przyjęta odpowiedź nie ma tak dobrego schematu kolorów jak twoje rozwiązanie. – jlafay

Powiązane problemy