WPF控件翻转

21

我有一个控件,主要由图像和按钮组成。 我想在图像的背面显示图像元数据,并且在按下按钮时控件水平翻转:

即:

输入图像描述

单击“信息”按钮...

输入图像描述

将图像绕轴旋转180度...

输入图像描述

显示图像的“背面”及其元数据(或任何其他内容)。

显然,当点击红色的“关闭”按钮时,图像会绕最后的180度旋转,以便再次显示图像。

在XAML中,我还没有真正做过3D,但我看不出这会太复杂...


你想要给它添加旋转动画吗? - Matt
是的和不是。我需要能够关闭动画,因为该应用程序将在本地和远程连接上使用。抱歉 - 没有表达清楚 :) - CatBusStop
5个回答

10

不需要使用三维技术。使用 ScaleEffect 并将水平缩放从 1 改为 -1 可以产生相同的视觉效果:

<Image RenderTransformOrigin="0.5,0.5">
    <Image.RenderTransform>
        <ScaleTransform ScaleX="-1" />
    </Image.RenderTransform>
</Image>
你可以通过动画ScaleX属性来实现旋转效果。您还应将其可见性从Visible更改为Hidden,反之亦然。使图像在旋转90度后消失,同时背面板应变得可见。

这只是翻转图像,提问者的图像有一个背面。 - H.B.
是的,但他是否可以使用相同的效果以相反的方式模拟图像的背面出现? - metalcam
我可以,但我认为仅使用ScaleX会使旋转看起来非常平面...只是试图弄清楚需要什么倾斜度来赋予它一些深度 :) - CatBusStop

9
一个可翻转的UserControl:
<UserControl x:Class="Test.UserControls.FlipControl" 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:local="clr-namespace:Test.UserControls" Name="control">
    <UserControl.Resources>
        <ContentControl x:Key="BackSide" Content="{Binding Source={x:Reference control}, Path=Back}" RenderTransformOrigin="0.5,0.5">
            <ContentControl.RenderTransform>
                <ScaleTransform ScaleX="-1" />
            </ContentControl.RenderTransform>
        </ContentControl>
    </UserControl.Resources>
    <ContentControl RenderTransformOrigin="0.5,0.5">
        <ContentControl.RenderTransform>
            <TransformGroup>
                <ScaleTransform x:Name="transform" ScaleX="1" />
            </TransformGroup>
        </ContentControl.RenderTransform>
        <ContentControl.Style>
            <Style TargetType="{x:Type ContentControl}">
                <Setter Property="Content" Value="{Binding ElementName=control, Path=Front}" />
                <Style.Triggers>
                    <DataTrigger Value="True">
                        <DataTrigger.Binding>
                            <Binding ElementName="transform" Path="ScaleX">
                                <Binding.Converter>
                                    <local:LessThanXToTrueConverter X="0" />
                                </Binding.Converter>
                            </Binding>
                        </DataTrigger.Binding>
                        <DataTrigger.Setters>
                            <Setter Property="Content" Value="{StaticResource BackSide}"/>
                        </DataTrigger.Setters>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ContentControl.Style>
    </ContentControl>
</UserControl>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Media.Animation;

namespace Test.UserControls
{
    /// <summary>
    /// Interaction logic for FlipControl.xaml
    /// </summary>
    public partial class FlipControl : UserControl, INotifyPropertyChanged
    {
        public static readonly DependencyProperty FrontProperty =
            DependencyProperty.Register("Front", typeof(UIElement), typeof(FlipControl), new UIPropertyMetadata(null));
        public UIElement Front
        {
            get { return (UIElement)GetValue(FrontProperty); }
            set { SetValue(FrontProperty, value); }
        }

        public static readonly DependencyProperty BackProperty =
            DependencyProperty.Register("Back", typeof(UIElement), typeof(FlipControl), new UIPropertyMetadata(null));
        public UIElement Back
        {
            get { return (UIElement)GetValue(BackProperty); }
            set { SetValue(BackProperty, value); }
        }

        public static readonly DependencyProperty FlipDurationProperty =
            DependencyProperty.Register("FlipDuration", typeof(Duration), typeof(FlipControl), new UIPropertyMetadata((Duration)TimeSpan.FromSeconds(0.5)));
        public Duration FlipDuration
        {
            get { return (Duration)GetValue(FlipDurationProperty); }
            set { SetValue(FlipDurationProperty, value); }
        }

        private bool _isFlipped = false;
        public bool IsFlipped
        {
            get { return _isFlipped; }
            private set
            {
                if (value != _isFlipped)
                {
                    _isFlipped = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("IsFlipped"));
                }
            }
        }

        private IEasingFunction EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut };

        public FlipControl()
        {
            InitializeComponent();
        }

        public void Flip()
        {
            var animation = new DoubleAnimation()
            {
                Duration = FlipDuration,
                EasingFunction = EasingFunction,
            };
            animation.To = IsFlipped ? 1 : -1;
            transform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
            IsFlipped = !IsFlipped;
            OnFlipped(new EventArgs());
        }

        public event EventHandler Flipped;

        protected virtual void OnFlipped(EventArgs e)
        {
            if (this.Flipped != null)
            {
                this.Flipped(this, e);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, e);
            }
        }
    }

    public class LessThanXToTrueConverter : IValueConverter
    {
        public double X { get; set; }

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (double)value < X;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

使用示例:

<uc:FlipControl x:Name="fc">
    <uc:FlipControl.Front>
        <Image Source="/Images/Default.ico" />
    </uc:FlipControl.Front>
    <uc:FlipControl.Back>
        <Image Source="/Images/Error.ico" />
    </uc:FlipControl.Back>
</uc:FlipControl>

fc.Flip();

是的,我一直在尝试X-Scale变换,虽然它看起来像旋转,但由于控件没有倾斜,它似乎看起来相当平面。我会继续调查,但可能会为简单起见选择这个 :) - CatBusStop
我通过两次翻转来“修复”了翻转背面的问题;你说得对,它看起来很平,但我怀疑一个简单的扭曲变换不会让它看起来好,透视变换会更好。 - H.B.
是的,为了获得正确的视角,它需要进行剪切,而要做到这一点需要使用3D技术。当我能够证明在UI上花费更多时间时,我会进一步调查它 :) - CatBusStop
+1 动画很棒,但使用单独的控件而不是图像作为 UIElement 时,返回控件无法正常工作... - Manish Dubey

6

虽然这是一个旧帖子,但你可以看一下 http://thriple.codeplex.com/, 这里有与之相关的控件。

Josh Smith 在2009年提供了一种实现此功能的控件。


1

看看这个项目链接

我正在等待Silverlight的平面投影进入WPF。


0

那个东西的交互逻辑很糟糕,所以虽然这个想法可能不错,但我建议彻底重写它。 - H.B.
你确定你能创建一个像那样运作的RenderTransform吗? - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接