【问题标题】:Is it possible to Animate a Binding?是否可以为绑定设置动画?
【发布时间】:2019-08-29 06:04:11
【问题描述】:

是否可以对我通过绑定获得的图片进行动画处理?由于我是 C# 和 WPF 的新手,我正在尝试使用绑定等功能。我希望旧图片淡出(可能是不透明度,但这是绑定的选项吗?)并且新图片淡入。或者更好地处理后面代码中的所有内容,我从文件夹中获取图像并绑定它之后。

<UserControl x:Class="Screensaver.ScreensaverControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Screensaver"
             mc:Ignorable="d" DataContext="{Binding RelativeSource={RelativeSource Self}}"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Image Visibility="Visible" Source="{Binding DisplayedImagePath}" Name="Bild" Stretch="Uniform" />

    </Grid>
</UserControl>

using System;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;

namespace Screensaver
{
    /// <summary>
    /// Interaction logic for ScreensaverControl.xaml
    /// </summary>
    public partial class ScreensaverControl : UserControl
    {
        private Timer _timer;

        public ScreensaverControl()
        {
            InitializeComponent();
            this.Loaded += ScreensaverControl_Loaded;
            this.Unloaded += ScreensaverControl_Unloaded;
        }

        private void ScreensaverControl_Loaded(object sender, RoutedEventArgs e)
        {
            _timer = new Timer(OnTimer, _timer, 10, Timeout.Infinite);
        }

        private void ScreensaverControl_Unloaded(object sender, RoutedEventArgs e)
        {
            _timer.Dispose();
            _timer = null;
        }

        private int _index = -1;
        private void OnTimer(object state)
        {
            try
            {
                var files = Directory.GetFiles(@"C:\Users\mhj\source\repos\Screensaver\Fotos\", "*.png");
                if (files.Length > 0)
                {
                    _index++;
                    if (_index >= files.Length)
                        _index = 0;

                    this.Dispatcher.Invoke(() => DisplayedImagePath = files[_index]);
                }
            }
            catch (Exception ex)
            {

            }
            finally
            {
                if (_timer != null)
                    _timer.Change(10000, Timeout.Infinite);
            }
        }

        public string DisplayedImagePath
        {
            get { return (string)GetValue(DisplayedImagePathProperty); }
            set { SetValue(DisplayedImagePathProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DisplayedImagePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisplayedImagePathProperty =
            DependencyProperty.Register("DisplayedImagePath", typeof(string), typeof(ScreensaverControl), new PropertyMetadata(null));
    }

}

【问题讨论】:

  • 您当然可以为 Image 元素的 Opacity 设置动画,但这与 Source 属性的 Binding 无关。要制作实际的混合效果,您还需要将两个 Image 元素放在一起,并为两者的 Opacity 设置动画,一个从 1 到 0,另一个从 0 到 1。
  • 但是我只绑定了一张图片,我应该在上面再放一张。我如何设置不透明度,因为我需要淡出效果,最好在后面的代码中做到这一点。可悲的是,我无法在 c# 中使用不透明度。
  • 还可以考虑使用 DispatcherTimer 而不是 System.Threading.Timer。它的 Tick 处理程序已经在 UI 线程中运行,因此不需要 Dispatcher.Invoke。
  • 那么是否应该有混合效果?
  • 您的视图模型中的图像属性是string 类型,这看起来也很奇怪。它应该是ImageSource,与Image 类的Source 属性完全相同。

标签: c# wpf image binding


【解决方案1】:

这是一个简单的屏幕保护程序控件的完整代码。它具有图像目录的依赖属性。您应该为更改间隔添加另一个依赖属性,也许还应该为混合效果添加第二个 Image。

XAML:

<UserControl x:Class="ScreenSaverControlTest.ScreenSaverControl" ...>
    <Grid>
        <Image x:Name="image1"/>
        <Image x:Name="image2"/>
    </Grid>
</UserControl>

和后面的代码:

public partial class ScreenSaverControl : UserControl
{
    public static readonly DependencyProperty ImageDirectoryProperty =
        DependencyProperty.Register(
            nameof(ImageDirectory), typeof(string), typeof(ScreenSaverControl),
            new PropertyMetadata(ImageDirectoryPropertyChanged));

    private readonly DispatcherTimer timer = new DispatcherTimer();
    private string[] imagePaths = new string[0];
    private int currentImageIndex = -1;

    public ScreenSaverControl()
    {
        InitializeComponent();

        timer.Interval = TimeSpan.FromSeconds(10);
        timer.Tick += (s, e) => NextImage();
        timer.Start();
    }

    public string ImageDirectory
    {
        get { return (string)GetValue(ImageDirectoryProperty); }
        set { SetValue(ImageDirectoryProperty, value); }
    }

    private static void ImageDirectoryPropertyChanged(
        DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var ssc = (ScreenSaverControl)o;
        var directory = (string)e.NewValue;

        if (!string.IsNullOrEmpty(directory) && Directory.Exists(directory))
        {
            ssc.imagePaths = Directory.GetFiles(directory, "*.jpg");
        }
        else
        {
            ssc.imagePaths = new string[0];
        }

        ssc.currentImageIndex = -1;
        ssc.NextImage();
    }

    private void NextImage()
    {
        if (imagePaths.Length > 0)
        {
            if (++currentImageIndex >= imagePaths.Length)
            {
                currentImageIndex = 0;
            }

            SetImage(new BitmapImage(new Uri(imagePaths[currentImageIndex])));
        }
    }

    private void SetImage(ImageSource imageSource)
    {
        var fadeOut = new DoubleAnimation(0d, TimeSpan.FromSeconds(1));
        var fadeIn = new DoubleAnimation(1d, TimeSpan.FromSeconds(1));
        var newImage = image1;
        var oldImage = image2;

        if (image1.Source != null)
        {
            newImage = image2;
            oldImage = image1;
        }

        fadeOut.Completed += (s, e) => oldImage.Source = null;

        oldImage.BeginAnimation(OpacityProperty, fadeOut);
        newImage.BeginAnimation(OpacityProperty, fadeIn);
        newImage.Source = imageSource;
    }
}

像这样使用它:

<local:ScreenSaverControl ImageDirectory="C:\Users\Public\Pictures\Sample Pictures"/>

【讨论】:

  • 我真的非常感谢您的帖子。所以我无法按照自己的方式去做,因为我想出代码的时间比我愿意承认的要长得多。我了解您的大部分代码,唯一让我明白的是什么是 s?我知道 e 是事件,s 也是一个吗?再次感谢您的帮助。
  • 它是 EventHandler 的 sender 参数。见这里:docs.microsoft.com/en-us/dotnet/api/…
  • 更改代码以使用具有混合效果的两个 Image 元素。
猜你喜欢
  • 2015-10-22
  • 2012-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-05
  • 1970-01-01
相关资源
最近更新 更多