WPF customized usercontrol ellipse,invoke in mvvm, and rotate smoothly via doubleanimation

install-package CommunityToolkit.Mvvm;

 

 

//usercontrol
<UserControl x:Class="WpfApp49.UCRotatedElp"
             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:WpfApp49"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <Storyboard x:Key="rotateStoryboard"
                    RepeatBehavior="Forever">
            <DoubleAnimation
                Storyboard.TargetName="rotateTransform"
                Storyboard.TargetProperty="Angle"
                From="0"
                To="360"
                Duration="{Binding UCElpRotateDuration,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                RepeatBehavior="Forever"/>
        </Storyboard>
    </UserControl.Resources>
    <Grid Loaded="Grid_Loaded">
        <Ellipse
                Width="{Binding UCElpWidthDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                Height="{Binding UCElpHeightDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
            <Ellipse.Fill>
                <ImageBrush ImageSource="{Binding UCElpImgSourceDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
            </Ellipse.Fill>
            <Ellipse.RenderTransform>
                <TransformGroup>
                    <RotateTransform x:Name="rotateTransform"
                                     CenterX="{Binding UCCenterXDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                     CenterY="{Binding UCCenterYDP,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">                        
                    </RotateTransform>
                </TransformGroup>
            </Ellipse.RenderTransform>
        </Ellipse>
    </Grid>
</UserControl>


//cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp49
{
    /// <summary>
    /// Interaction logic for UCRotatedElp.xaml
    /// </summary>
    public partial class UCRotatedElp : UserControl
    {
        public UCRotatedElp()
        {
            InitializeComponent();
            this.DataContext=this;
        }



        public Duration UCElpRotateDuration
        {
            get { return (Duration)GetValue(UCElpRotateDurationProperty); }
            set { SetValue(UCElpRotateDurationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UCElpRotateDuration.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCElpRotateDurationProperty =
            DependencyProperty.Register("UCElpRotateDuration", typeof(Duration),
                typeof(UCRotatedElp), new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(16))));



        public double UCElpWidthDP
        {
            get { return (double)GetValue(UCElpWidthDPProperty); }
            set { SetValue(UCElpWidthDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UCElpWidthDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCElpWidthDPProperty =
            DependencyProperty.Register("UCElpWidthDP", typeof(double),
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));




        public double UCElpHeightDP
        {
            get { return (double)GetValue(UCElpHeightDPProperty); }
            set { SetValue(UCElpHeightDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UCElpHeightDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCElpHeightDPProperty =
            DependencyProperty.Register("UCElpHeightDP", typeof(double),
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));




        public ImageSource UCElpImgSourceDP
        {
            get { return (ImageSource)GetValue(UCElpImgSourceDPProperty); }
            set { SetValue(UCElpImgSourceDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UCElpImgSourceDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCElpImgSourceDPProperty =
            DependencyProperty.Register("UCElpImgSourceDP", typeof(ImageSource),
                typeof(UCRotatedElp), new PropertyMetadata(null));




        public double UCCenterXDP
        {
            get { return (double)GetValue(UCCenterXDPProperty); }
            set { SetValue(UCCenterXDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UCCenterXDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCCenterXDPProperty =
            DependencyProperty.Register("UCCenterXDP", typeof(double),
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));





        public double UCCenterYDP
        {
            get { return (double)GetValue(UCCenterYDPProperty); }
            set { SetValue(UCCenterYDPProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UCCenterYDP.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UCCenterYDPProperty =
            DependencyProperty.Register("UCCenterYDP", typeof(double),
                typeof(UCRotatedElp), new PropertyMetadata(0.0d));

        private void Grid_Loaded(object sender, RoutedEventArgs e)
        {
            var storyBoard = Resources["rotateStoryboard"] as Storyboard;
            if (storyBoard!=null)
            {
                storyBoard.Begin();
            }
        }
    }
}


//Mainwindow
//xaml
<Window x:Class="WpfApp49.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"
        WindowState="Maximized"
        xmlns:local="clr-namespace:WpfApp49"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:UCRotatedElp
            UCElpRotateDuration="{Binding DataContext.ElpRotateDuration,RelativeSource={RelativeSource AncestorType=Window},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"            
            UCElpWidthDP="{Binding DataContext.ElpWidth,
            RelativeSource={RelativeSource AncestorType=Window},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"            
            UCElpHeightDP="{Binding DataContext.ElpHeight,RelativeSource={RelativeSource AncestorType=Window},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"            
            UCCenterXDP="{Binding DataContext.CenterX,RelativeSource={RelativeSource AncestorType=Window},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"            
            UCCenterYDP="{Binding DataContext.CenterY,RelativeSource={RelativeSource AncestorType=Window},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"            
            UCElpImgSourceDP="{Binding DataContext.ImgSource,RelativeSource={RelativeSource AncestorType=Window},
            Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>


//cs
using CommunityToolkit.Mvvm.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace WpfApp49
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var vm = new MainVM(this);
            this.DataContext=vm;
        }
    }

    public partial class MainVM : ObservableObject
    {

        [ObservableProperty]
        private double elpWidth;

        [ObservableProperty]
        private double elpHeight;

        [ObservableProperty]
        private ImageSource imgSource;

        [ObservableProperty]
        private double centerX;

        [ObservableProperty]
        private double centerY;

        [ObservableProperty]
        private Duration elpRotateDuration;

        private Window win;
        private double maxWidth, maxHeight;
        public MainVM(Window winValue)
        {
            win= winValue;
            if (win!=null)
            {
                win.Loaded+=Win_Loaded;
            }
        }

        private void Win_Loaded(object sender, RoutedEventArgs e)
        {
            maxWidth=win.ActualWidth;
            maxHeight=win.ActualHeight;
            ElpWidth=maxHeight-100;
            ElpHeight=maxHeight-100;
            CenterX=ElpWidth/2;
            CenterY=ElpHeight/2;
            ElpRotateDuration=TimeSpan.FromSeconds(12);
            ImgSource=GetImgSourceViaUrl();
        }

        private ImageSource GetImgSourceViaUrl(string imgUrl="")
        {
            BitmapImage bmi = new BitmapImage();
            string resourceFileName = "WpfApp49.Images.1.jpg";
            using(var stream=Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceFileName))
            {                
                bmi.BeginInit();
                bmi.StreamSource=stream;
                bmi.EndInit();
                if (bmi.CanFreeze)
                {
                    bmi.Freeze();
                }
            }
            return bmi;
        }
    }
}

 

 

 

 

 

 

image

 

 

 

image

 

posted @ 2025-08-20 15:00  FredGrit  阅读(3)  评论(0)    收藏  举报