【问题标题】:WPF: Hiding object causes brief flash before disappearingWPF:隐藏对象会在消失前导致短暂闪烁
【发布时间】:2017-02-21 18:25:15
【问题描述】:

我有一个简单的按钮样式,它具有绑定到 bool 属性的数据触发器,如果​​属性为 false,它会使用简单的淡出动画隐藏按钮,反之亦然。

但是由于一些未知的原因,当我第一次执行一些将 bool 值设置为 false 的任务时。它会在淡出之前短暂闪烁。将其设置为 true 后,一切都按预期进行。

我的风格是

 <Style x:Key="CustomButtonStyle" TargetType="{x:Type Button}" >
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsButtonVisible}" Value="true">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetProperty="Opacity" >
                        <DoubleAnimation Duration="0:0:0.2" To="1"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard Storyboard.TargetProperty="Opacity" >
                        <DoubleAnimation Duration="0:0:0.2" To="0"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.ExitActions>
        </DataTrigger>
        <Trigger Property="Opacity" Value="0">
            <Setter Property="Visibility" Value="Collapsed"></Setter>
        </Trigger>
        <Trigger Property="Opacity" Value="1" >
            <Setter Property="Visibility" Value="Visible"></Setter>
        </Trigger>
    </Style.Triggers>
    <Style.Setters>
        <Setter Property="Height" Value="93"/>
        <Setter Property="Width" Value="93"/>
        <Setter Property="Opacity" Value="0"/>
     </Style.Setters>
</Style>

注意:- IsButtonVisible 的默认值为 true

【问题讨论】:

  • &lt;DoubleAnimation Duration="0:0:0.2" To="0"/&gt; 更改为&lt;DoubleAnimation Duration="0:0:0" To="0"/&gt; 会消除闪存吗?
  • @KyleHancock 不,它没有
  • 我测试了这种风格,一切正常。检查除此样式之外的代码。发布任何可能丢失的相关代码。
  • 我想知道淡入应该如何工作。想象一下,当 Button 先前已淡出时,Opacity 为 0,因此 Visibility 已折叠(由于 Trigger)。如果随后通过将 Opacity 设置为 1 的动画使 Button 淡入,则在 Opacity 动画以值 1 结束(触发 Visibility)之前,Visibility 不会变为 Visible。
  • 我得到了与@KyleHancock 相同的结果。我没有看到任何闪光。你的代码隐藏是什么样的?我愿意在您的代码中的某个地方打赌 IsButtonVisible 属性会连续多次设置。例如,它可能被设置为 false(触发淡出),然后几乎立即设置为 true(取消淡出,给您“闪光”),然后再次回到 false(允许淡出实际发生) .在您的 IsButtonVisible 设置器中,我建议您执行 Debug.WriteLine 或设置断点以查看那里发生了什么。

标签: wpf animation data-binding storyboard datatrigger


【解决方案1】:

为了防止在动画执行时设置绑定属性IsButtonVisible,您可以将以下内容添加到您的ViewModel

private bool _animationInProgress = false;
private readonly object _animationLock = new object();
private bool _isButtonVisible = true;

public bool IsButtonVisible {
    get { return _isButtonVisible; }
    set {
        lock (_animationLock) {
            if (value == _isButtonVisible || _animationInProgress) return;
            _animationInProgress = true;
        }
        _isButtonVisible = value;
        OnPropertyChanged();
        Timer animationDoneTimer = new Timer {Interval = 200, Enabled = true, AutoReset = false};
        animationDoneTimer.Elapsed += (sender, args) => {
                                          lock (_animationLock) {
                                              _animationInProgress = false;
                                          }
                                      };

    }
}

第二件事我会删除Trigger

<Trigger Property="Opacity" Value="1" >
    <Setter Property="Visibility" Value="Visible"></Setter>
</Trigger>

对于行为,您希望将Visibility 设置为Opacity 上的Collapsed == 0 和Visibility 设置为VisibleOpacity =! 0 你应该这样做:

    ...
        <Trigger Property="Opacity" Value="0">
            <Setter Property="Visibility" Value="Collapsed" />
        </Trigger>
        <!-- Trigger removed -->
    </Style.Triggers>
    <Style.Setters>
        <!-- Visibilities value if Trigger Opacity == 0 does not fire  -->
        <Setter Property="Visibility" Value="Visible" />

        <Setter Property="Height" Value="93"/>
        <Setter Property="Width" Value="93"/>
        <Setter Property="Opacity" Value="0"/>
    </Style.Setters>
</Style>

【讨论】:

    【解决方案2】:

    为什么有两个DataTrigger?试试这个解决方案,也许它可以解决你的问题。

            <Style x:Key="DefaultButtonStyle" TargetType="{x:Type Button}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsVisible}" Value="true">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard FillBehavior="HoldEnd" Storyboard.TargetProperty="Opacity">
                                <DoubleAnimation Duration="0:0:0.2"  To="1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard Storyboard.TargetProperty="Opacity" >
                                <DoubleAnimation Duration="0:0:0.2"  To="0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger> 
                <Trigger Property="Opacity" Value="0">
                    <Setter Property="Visibility" Value="Collapsed"></Setter>
                </Trigger>
                <Trigger Property="Opacity" Value="1">
                    <Setter Property="Visibility" Value="Visible"></Setter>
                </Trigger>
            </Style.Triggers>
            <Style.Setters>
                <Setter Property="Height" Value="93"/>
                <Setter Property="Width" Value="93"/>
                <Setter Property="Opacity" Value="0"/>
            </Style.Setters>
        </Style>
    

    编辑:

    XAML
    <Window x:Class="WpfApplication1.MainWindow"
        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"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="279.716" Width="279.784"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Window.Resources>
        <Style x:Key="ButtonStyleTrue" TargetType="{x:Type Button}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding VisibleTrue}" Value="true">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard FillBehavior="HoldEnd" Storyboard.TargetProperty="Opacity">
                                <DoubleAnimation Duration="0:0:0.2"  To="1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard Storyboard.TargetProperty="Opacity" >
                                <DoubleAnimation Duration="0:0:0.2"  To="0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger>
                <Trigger Property="Opacity" Value="0">
                    <Setter Property="Visibility" Value="Collapsed"></Setter>
                </Trigger>
                <Trigger Property="Opacity" Value="1">
                    <Setter Property="Visibility" Value="Visible"></Setter>
                </Trigger>
            </Style.Triggers>
            <Style.Setters>
                <Setter Property="Height" Value="93"/>
                <Setter Property="Width" Value="93"/>
                <Setter Property="Opacity" Value="0"/>
            </Style.Setters>
        </Style>
        <Style x:Key="ButtonStyleFalse" TargetType="{x:Type Button}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding VisibleFalse}" Value="true">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard FillBehavior="HoldEnd" Storyboard.TargetProperty="Opacity">
                                <DoubleAnimation Duration="0:0:0.2"  To="1"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard Storyboard.TargetProperty="Opacity" >
                                <DoubleAnimation Duration="0:0:0.2"  To="0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger>
                <Trigger Property="Opacity" Value="0">
                    <Setter Property="Visibility" Value="Collapsed"></Setter>
                </Trigger>
                <Trigger Property="Opacity" Value="1">
                    <Setter Property="Visibility" Value="Visible"></Setter>
                </Trigger>
            </Style.Triggers>
            <Style.Setters>
                <Setter Property="Height" Value="93"/>
                <Setter Property="Width" Value="93"/>
                <Setter Property="Opacity" Value="0"/>
            </Style.Setters>
        </Style>
    </Window.Resources>
    <Grid>
        <Button Content="Button" HorizontalAlignment="Left" Margin="187,11,0,0" VerticalAlignment="Top" Width="75" Click="Button_OnClick"/>
        <Button Style="{StaticResource ButtonStyleFalse}" Content="Button" HorizontalAlignment="Left" Margin="47,66,0,0" VerticalAlignment="Top" Width="75"/>
        <TextBlock x:Name="textBlock_true" HorizontalAlignment="Left" Margin="193,68,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
        <Button Style="{StaticResource ButtonStyleTrue}" Content="Button" HorizontalAlignment="Left" Margin="47,143,0,0" VerticalAlignment="Top" Width="75"/>
        <TextBlock x:Name="textBlock_false" HorizontalAlignment="Left" Margin="193,145,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
    </Grid>
    

    代码背后
    using System.ComponentModel;
    using System.Windows;
    
    namespace WpfApplication1
    {
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
    
        /// <summary>
        /// Initalvalue is true;
        /// </summary>
        public bool VisibleTrue
        {
            get { return _VisibleTrue; }
            set
            {
                if (_VisibleTrue == value) return;
                _VisibleTrue = value;
                textBlock_true.Text = value ? "True" : "False";              
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("VisibleTrue"));
            }
        }
        private bool _VisibleTrue = true;
    
    
    
        /// <summary>
        /// Initialvalue is false
        /// </summary>
        public bool VisibleFalse
        {
            get { return _VisibleFalse; }
            set
            {
                if (_VisibleFalse == value) return;
                _VisibleFalse = value;
                textBlock_false.Text = value ? "True" : "False";
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("VisibleFalse"));
            }
        }
        private bool _VisibleFalse;
    
    
        public MainWindow()
        {
            InitializeComponent();
    
            textBlock_true.Text = "Application started";
            textBlock_false.Text = "Application started";
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            VisibleTrue = !VisibleTrue;
            VisibleFalse = !VisibleTrue;
        }
    }
    }
    
    预习

    【讨论】:

    • 我将发布带有示例的编辑。但如果我的代码没有帮助,您可以添加更多代码细节。否则我错了。
    猜你喜欢
    • 2015-08-03
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-25
    • 2011-12-27
    • 1970-01-01
    相关资源
    最近更新 更多