У меня есть пользовательский элемент управления WPF, определенный в проекте библиотеки элементов управления WPF, который называется Flasher.По сути, это прямоугольник, свойство Fill мигает между двумя цветами, как мигающий индикатор на консоли.Вот шаблон для элемента управления, который находится в файле Generic.xaml для библиотеки:
<Style TargetType="{x:Type local:Flasher}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Flasher}">
<Grid Name="LayoutRoot">
<Grid.Resources>
<Storyboard x:Key="FlashingStoryboard" AutoReverse="True" RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="Flasher"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="00:00:00.5"
Value="{Binding Path=FlashColor, RelativeSource={RelativeSource AncestorType={x:Type local:Flasher}}}"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimation Duration="00:00:00.05"
From="0" To="10"
Storyboard.TargetName="FlasherBlur"
Storyboard.TargetProperty="Radius">
</DoubleAnimation>
</Storyboard>
</Grid.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="FlashStates">
<VisualState x:Name="Flashing" Storyboard="{DynamicResource ResourceKey=FlashingStoryboard}"/>
<VisualState x:Name="Stopped"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle Fill="{TemplateBinding Fill}"
Name="Flasher"
Stroke="{TemplateBinding Stroke}"
StrokeThickness="{TemplateBinding StrokeThickness}">
<Rectangle.Effect>
<BlurEffect x:Name="FlasherBlur" Radius="0" />
</Rectangle.Effect>
</Rectangle>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Вот код для элемента управления:
public partial class Flasher : Control {
public static readonly DependencyProperty FillProperty =
DependencyProperty.Register( "Fill", typeof( Brush ), typeof( Flasher),
new FrameworkPropertyMetadata ( new SolidColorBrush( Colors.Silver), FrameworkPropertyMetadataOptions.AffectsRender ) );
public static readonly DependencyProperty FlashColorProperty =
DependencyProperty.Register( "FlashColor", typeof( Color ), typeof( Flasher ),
new FrameworkPropertyMetadata( Colors.Transparent, FrameworkPropertyMetadataOptions.AffectsRender ) );
public static readonly DependencyProperty FlashDurationProperty =
DependencyProperty.Register( "FlashDuration", typeof( TimeSpan ), typeof( Flasher ), new FrameworkPropertyMetadata( TimeSpan.MinValue ) );
public static readonly DependencyProperty StrokeProperty =
DependencyProperty.Register( "Stroke", typeof( Brush ), typeof( Flasher ),
new FrameworkPropertyMetadata( new SolidColorBrush( Colors.Silver ), FrameworkPropertyMetadataOptions.AffectsRender ) );
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register( "StrokeThickness", typeof( double ), typeof( Flasher ),
new FrameworkPropertyMetadata( 0.0, FrameworkPropertyMetadataOptions.AffectsRender ) );
protected Application App {
get { return Application.Current; }
}
protected ILog Log {
get { return (ILog) App.Properties[ "Log" ]; }
}
public Brush Fill {
get { return (Brush) GetValue( FillProperty ); }
set { SetValue( FillProperty, value ); }
}
public Color FlashColor {
get { return (Color) GetValue( FlashColorProperty ); }
set { SetValue( FlashColorProperty, value ); }
}
public TimeSpan FlashDuration {
get { return (TimeSpan) GetValue( FlashDurationProperty ); }
set { SetValue( FlashDurationProperty, value ); }
}
private bool flashing = false;
public bool IsFlashing {
get { return flashing; }
set {
flashing = value;
FrameworkElement grid = Template.FindName( "LayoutRoot", this ) as FrameworkElement;
if ( flashing ) {
if ( !VisualStateManager.GoToElementState( grid, "Flashing", true ) ) {
Log.Debug( "Flasher.cs: Visual State Manager transition failed." );
}
if ( FlashDuration > TimeSpan.MinValue ) {
ThreadPool.QueueUserWorkItem( WaitForDuration, FlashDuration );
}
} else {
if ( !VisualStateManager.GoToElementState( grid, "Stopped", true ) ) {
Log.Debug( "Flasher.cs: Visual State Manager transition failed." );
}
}
}
}
public Brush Stroke {
get { return (Brush) GetValue( StrokeProperty ); }
set { SetValue( StrokeProperty, value ); }
}
public double StrokeThickness {
get { return (double) GetValue( StrokeThicknessProperty ); }
set { SetValue( StrokeThicknessProperty, value ); }
}
public Flasher() : base() {}
static Flasher() {
DefaultStyleKeyProperty.OverrideMetadata( typeof( Flasher ), new FrameworkPropertyMetadata( typeof( Flasher ) ) );
}
private void TurnFlashingOff() {
// Set IsFlashing to false
IsFlashing = false;
}
private void WaitForDuration( object state ) {
System.Threading.Thread.Sleep( (TimeSpan) state );
Dispatcher.BeginInvoke( new Action( TurnFlashingOff ) );
}
}
Это все работалонесколько месяцев назад, но это не работает сейчас.То есть раньше я видел, как флешер меняет цвета между двумя цветами, которые я установил в окне, в котором используется элемент управления.Я установил контрольные точки в установщике IsFlashing, и я знаю, что вызов FindName возвращает Grid, и я знаю, что вызовы VisualStateManager работают, поэтому я не понимаю, почему я не вижу изменения цветов.Это меня сильно озадачило.
Плюс, похоже, Snoop не может найти окно, в котором возникла проблема.Это не главное окно моего приложения, а немодальное всплывающее окно.По сути, окно с проблемой происходит из окна и создается и отображается со следующим кодом:
if ( Window == null ) {
Window = new MyDialog();
// Set some program-specific window properties that don't affect the display here . . .
Window.Show();
}
То есть Snoop был бесполезен.
Если в коде нет явных ошибокЯ опубликовал, а затем мне придется поискать проблему в другом месте моего кода.
Спасибо за любую помощь, которую вы можете оказать.
Тони