//usercontrol.xaml
<UserControl x:Class="WpfApp190.RotatedCircle"
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:WpfApp190"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Ellipse x:Name="elp"
MouseDown="Ellipse_MouseDown"
MouseMove="Ellipse_MouseMove"
MouseUp="Ellipse_MouseUp"
Width="{Binding UCElpWidth,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Height="{Binding UCElpHeight,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
RenderTransformOrigin="0.5,0.5">
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding UCImgSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</Ellipse.Fill>
<Ellipse.RenderTransform>
<RotateTransform x:Name="elpRotate"/>
</Ellipse.RenderTransform>
</Ellipse>
</Grid>
</UserControl>
//usercontrol.xaml.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.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
namespace WpfApp190
{
/// <summary>
/// Interaction logic for RotatedCircle.xaml
/// </summary>
public partial class RotatedCircle : UserControl
{
public RotatedCircle()
{
InitializeComponent();
this.DataContext = this;
this.Loaded += RotatedCircle_Loaded;
this.SizeChanged += RotatedCircle_SizeChanged;
}
private void RotatedCircle_SizeChanged(object sender, SizeChangedEventArgs e)
{
Init();
}
private void RotatedCircle_Loaded(object sender, RoutedEventArgs e)
{
Init();
}
private void Init()
{
var ucContent = this.Content as FrameworkElement;
if (ucContent!=null)
{
UCElpWidth = ucContent.ActualHeight;
UCElpHeight= ucContent.ActualHeight;
originPt=new Point(ucContent.ActualWidth/2, ucContent.ActualHeight/2);
}
}
public double UCElpWidth
{
get { return (double)GetValue(UCElpWidthProperty); }
set { SetValue(UCElpWidthProperty, value); }
}
// Using a DependencyProperty as the backing store for UCElpWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCElpWidthProperty =
DependencyProperty.Register("UCElpWidth", typeof(double),
typeof(RotatedCircle), new PropertyMetadata(0.0d));
public double UCElpHeight
{
get { return (double)GetValue(UCElpHeightProperty); }
set { SetValue(UCElpHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for UCElpHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCElpHeightProperty =
DependencyProperty.Register("UCElpHeight", typeof(double),
typeof(RotatedCircle), new PropertyMetadata(0.0d));
public ImageSource UCImgSource
{
get { return (ImageSource)GetValue(UCImgSourceProperty); }
set { SetValue(UCImgSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for UCImgSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCImgSourceProperty =
DependencyProperty.Register("UCImgSource", typeof(ImageSource),
typeof(RotatedCircle), new PropertyMetadata(GetDefaultImageSource()));
public double UCElpAngle
{
get { return (double)GetValue(UCElpAngleProperty); }
set { SetValue(UCElpAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for UCElpAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UCElpAngleProperty =
DependencyProperty.Register("UCElpAngle", typeof(double),
typeof(RotatedCircle), new PropertyMetadata(0.0d));
private static object GetDefaultImageSource()
{
string imgFile = @"../../Images/1.jpg";
if (!File.Exists(imgFile))
{
return null;
}
BitmapImage bmi = new BitmapImage();
bmi.BeginInit();
bmi.UriSource=new Uri(imgFile,UriKind.RelativeOrAbsolute);
bmi.EndInit();
if(bmi.CanFreeze)
{
bmi.Freeze();
}
return bmi;
}
private Point prevPt;
private Point originPt;
private void Ellipse_MouseDown(object sender, MouseButtonEventArgs e)
{
if(e.LeftButton == MouseButtonState.Pressed)
{
elp.CaptureMouse();
prevPt = e.GetPosition(this);
}
}
private void Ellipse_MouseMove(object sender, MouseEventArgs e)
{
if(e.LeftButton == MouseButtonState.Pressed)
{
Vector prevVec = Point.Subtract(prevPt, originPt);
Point newPt = e.GetPosition(this);
Vector newVec = Point.Subtract(newPt, originPt);
double deltaAngle = Vector.AngleBetween(prevVec, newVec);
elpRotate.Angle += deltaAngle;
UCElpAngle = elpRotate.Angle;
prevPt = newPt;
}
}
private void Ellipse_MouseUp(object sender, MouseButtonEventArgs e)
{
if(e.LeftButton==MouseButtonState.Released)
{
elp.ReleaseMouseCapture();
}
}
}
}
//window.xaml
<Window x:Class="WpfApp190.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:WpfApp190"
mc:Ignorable="d"
WindowState="Maximized"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:RotatedCircle
UCElpAngle="{Binding DataContext.ElpAngle,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},
Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</Window>
//window.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
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.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp190
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.Title = "0";
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName]string propName="")
{
var handler=PropertyChanged;
if(handler!=null)
{
handler?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
private double elpAngle;
public double ElpAngle
{
get
{
return elpAngle;
}
set
{
if(value!=elpAngle)
{
elpAngle = value;
OnPropertyChanged(nameof(ElpAngle));
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
{
this.Title = Math.Round(ElpAngle, 2).ToString();
}));
}
}
}
}
}