在 Windows RT 中使用 Ellipse 进行剪辑并将其绑定到我的用户控件中

Clipping Using Ellipse and binding it inside my user control in Windows RT

我有一张图片,我正在使用我非常成功的椭圆裁剪鼠标区域。

但我希望该椭圆成为我的用户控件的一部分,并且用户控件应随我的手指移动,并且剪辑椭圆应在用户控件内。 完整的项目可以从here

下载

我的 UserControl 的 XAML

<UserControl
    x:Class="App78.Magnifier"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App78"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Height="230"
    Width="170">


    <Grid Height="230" Width="170">
        <Path Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z"
              Fill="#FFF4F4F5"
              Stretch="Fill"
              Stroke="Black"
              UseLayoutRounding="False"
              Height="227"
              Width="171" ></Path>
            <Ellipse x:Name="MagnifierEllipse" x:FieldModifier="public"  Opacity="1" Visibility="Visible" HorizontalAlignment="Left" VerticalAlignment="Top" IsHitTestVisible="False" Width="150" Height="150" Stroke="White" StrokeThickness="3" Margin="11,8,0,0" >
                <Ellipse.RenderTransform>
                    <TranslateTransform x:Name="MagnifierTransform" x:FieldModifier="public"/>
                </Ellipse.RenderTransform>

                <Ellipse.Fill>
                    <ImageBrush
                    ImageSource="http://blog.al.com/space-news/2009/04/iss015e22574.jpg"
                    Stretch="None"
                    AlignmentX="Left"
                    AlignmentY="Top">
                        <ImageBrush.Transform>
                            <TransformGroup>
                                <TranslateTransform x:FieldModifier="public"
                                x:Name="PositionTransform"/>
                                <ScaleTransform x:FieldModifier="public"
                                x:Name="ZoomTransform"/>
                                <TranslateTransform x:FieldModifier="public"
                                x:Name="CenterTransform" />
                            </TransformGroup>
                        </ImageBrush.Transform>
                    </ImageBrush>
                </Ellipse.Fill>
            </Ellipse>

    </Grid>
</UserControl>

我的MainPage.XAML

<Page
    x:Class="App78.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App78"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d">

    <Grid
        x:Name="LayoutGrid"
        Margin="0,0"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
        Holding="LayoutGrid_Holding"
        PointerMoved="LayoutGrid_OnPointerMoved"
        PointerWheelChanged="LayoutGrid_OnPointerWheelChanged">
        <Image
            x:Name="BigImage"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Stretch="Uniform"
            Source="http://blog.al.com/space-news/2009/04/iss015e22574.jpg" />


                <!--<Ellipse 
            x:Name="MagnifierEllipse"
            Opacity="1"
            Visibility="Collapsed"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            IsHitTestVisible="False"
            Width="150"
            Height="150"
            Stroke="White"
            StrokeThickness="3"
            Margin="-100">
                    <Ellipse.RenderTransform>
                        <TranslateTransform
                    x:Name="MagnifierTransform"/>
                    </Ellipse.RenderTransform>
                    <Ellipse.Fill>
                        <ImageBrush
                    ImageSource="http://blog.al.com/space-news/2009/04/iss015e22574.jpg"
                    Stretch="None"
                    AlignmentX="Left"
                    AlignmentY="Top">
                            <ImageBrush.Transform>
                                <TransformGroup>
                                    <TranslateTransform
                                x:Name="PositionTransform"/>
                                    <ScaleTransform
                                x:Name="ZoomTransform"/>
                                    <TranslateTransform
                                x:Name="CenterTransform" />
                                </TransformGroup>
                            </ImageBrush.Transform>
                        </ImageBrush>
                    </Ellipse.Fill>
                </Ellipse>-->
        <local:Magnifier x:Name="MagnifierTip" Visibility="Visible" />
    </Grid>
</Page>

请参阅 Ellipse 注释部分 ,如果我取消注释,我会清楚地看到正在剪辑的 Ellipse。

我的主要要求是在用户控件中获取椭圆,请参阅video以获得更多说明

我的MainPage.XAML.CS有如下代码

using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

namespace App78
{
    public sealed partial class MainPage : Page
    {
        private double zoomScale = 2;
        private double pointerX = 0;
        private double pointerY = 0;
        private const double MinZoomScale = .25;
        private const double MaxZoomScale = 32;


        public MainPage()
        {
            this.InitializeComponent();

            var bi = (BitmapImage)BigImage.Source;
            bi.ImageOpened += bi_ImageOpened;
            this.SizeChanged += MainPage_SizeChanged;
        }

        void MainPage_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
        {
            this.UpdateImageLayout();
        }

        void bi_ImageOpened(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            this.UpdateImageLayout();
        }

        private void UpdateImageLayout()
        {
            var bi = (BitmapImage)BigImage.Source;
            if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
                bi.PixelHeight < this.LayoutGrid.ActualHeight)
            {
                this.BigImage.Stretch = Stretch.None;
            }
            else
            {
                this.BigImage.Stretch = Stretch.Uniform;
            }

            this.UpdateMagnifier();
        }

        private void LayoutGrid_OnPointerMoved(object sender, PointerRoutedEventArgs e)
        {
           // MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
            var point = e.GetCurrentPoint(this.LayoutGrid);
            this.pointerX = point.Position.X;
            this.pointerY = point.Position.Y;
            this.UpdateMagnifier();
        }

        private void UpdateMagnifier()
        {
            var bi = (BitmapImage)BigImage.Source;

            double offsetX = 0;
            double offsetY = 0;
            double imageScale = 1;

            var imageRatio = (double)bi.PixelWidth / bi.PixelHeight;
            var gridRatio = this.LayoutGrid.ActualWidth / this.LayoutGrid.ActualHeight;

            if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
                bi.PixelHeight < this.LayoutGrid.ActualHeight)
            {
                offsetX = 0.5 * (this.LayoutGrid.ActualWidth - bi.PixelWidth);
                offsetY = 0.5 * (this.LayoutGrid.ActualHeight - bi.PixelHeight);
                //imageScale = 1; - remains
            }
            else if (imageRatio < gridRatio)
            {
                offsetX = 0.5 * (this.LayoutGrid.ActualWidth - imageRatio * this.LayoutGrid.ActualHeight);
                offsetY = 0;
                imageScale = BigImage.ActualHeight / bi.PixelHeight;
            }
            else
            {
                offsetX = 0;
                offsetY = 0.5 * (this.LayoutGrid.ActualHeight - this.LayoutGrid.ActualWidth / imageRatio);
                imageScale = BigImage.ActualWidth / bi.PixelWidth;
            }

            MagnifierTip.MagnifierTransform.X = this.pointerX;
           MagnifierTip.MagnifierTransform.Y = this.pointerY;
           MagnifierTip.PositionTransform.X = (-this.pointerX + offsetX) / imageScale;
           MagnifierTip.PositionTransform.Y = (-this.pointerY + offsetY) / imageScale;
           MagnifierTip. ZoomTransform.ScaleX = imageScale * zoomScale;
           MagnifierTip.ZoomTransform.ScaleY = imageScale * zoomScale;
           MagnifierTip.CenterTransform.X = MagnifierTip.MagnifierEllipse.ActualWidth / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;
           MagnifierTip.CenterTransform.Y = MagnifierTip.MagnifierEllipse.ActualHeight / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;
        }

        private void LayoutGrid_OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
        {
            if (e.GetCurrentPoint(this.LayoutGrid).Properties.MouseWheelDelta > 0)
            {
                zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale * 1.2));
            }
            else
            {
                zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale / 1.2));
            }

            this.UpdateMagnifier();
        }

        private void LayoutGrid_Holding(object sender, HoldingRoutedEventArgs e)
        {
          //  MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Visible;


        }
    }
}

我认为您需要将 MagnifierTransform 放到放大镜用户控件的 "root" 网格中。
另外,在我看来似乎不需要 CenterTransform。
另一个最后的变化是在 MainPage 中,使用户控件与 Top/Left 对齐,以便 TranslateTransforms 有意义。

作为奖励,我得到了更新的项目here , also with pointer pressed/released events to show/hide the magnifier. Be warned that "Holding" doesn't work with most mouse devices. Source: link
我还添加了对我的更改的评论(评论以 DV: 开头)。 它并不完美,显然您还有很多需要实施的地方,但希望这就是您所需要的。

对于不想下载该项目的人,我将在此处保留更新的代码:
MainPage.xaml

<Page
    x:Class="App78.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App78"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid
        x:Name="LayoutGrid"
        Margin="0,0"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
        Holding="LayoutGrid_Holding"
        PointerMoved="LayoutGrid_OnPointerMoved"
        PointerWheelChanged="LayoutGrid_OnPointerWheelChanged"
        PointerPressed="LayoutGrid_OnPointerPressed"
        PointerReleased="LayoutGrid_OnPointerReleased">
        <Image
            x:Name="BigImage"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Stretch="Uniform"
            Source="http://blog.al.com/space-news/2009/04/iss015e22574.jpg" />

        <local:Magnifier VerticalAlignment="Top" HorizontalAlignment="Left" x:Name="MagnifierTip" Visibility="Collapsed" />
    </Grid>
</Page>

MainPage.xaml.cs

using System;
using System.Diagnostics;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

namespace App78
{
    public sealed partial class MainPage : Page
    {
        private double zoomScale = 2;
        private double pointerX = 0;
        private double pointerY = 0;
        private const double MinZoomScale = .25;
        private const double MaxZoomScale = 32;


        public MainPage()
        {
            this.InitializeComponent();

            var bi = (BitmapImage)BigImage.Source;
            bi.ImageOpened += bi_ImageOpened;
            this.SizeChanged += MainPage_SizeChanged;
        }

        void MainPage_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
        {
            this.UpdateImageLayout();
        }

        void bi_ImageOpened(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            this.UpdateImageLayout();
        }

        private void UpdateImageLayout()
        {
            var bi = (BitmapImage)BigImage.Source;
            if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
                bi.PixelHeight < this.LayoutGrid.ActualHeight)
            {
                this.BigImage.Stretch = Stretch.None;
            }
            else
            {
                this.BigImage.Stretch = Stretch.Uniform;
            }

            this.UpdateMagnifier();
        }

        private void LayoutGrid_OnPointerMoved(object sender, PointerRoutedEventArgs e)
        {
            //DV: If pointer is not in contact we can ignore it
            if (!e.Pointer.IsInContact) { return; }

            var point = e.GetCurrentPoint(this.LayoutGrid);
            this.pointerX = point.Position.X;
            this.pointerY = point.Position.Y;
            this.UpdateMagnifier();
        }

        private void UpdateMagnifier()
        {
            var bi = (BitmapImage)BigImage.Source;

            double offsetX = 0;
            double offsetY = 0;
            double imageScale = 1;

            var imageRatio = (double)bi.PixelWidth / bi.PixelHeight;
            var gridRatio = this.LayoutGrid.ActualWidth / this.LayoutGrid.ActualHeight;

            if (bi.PixelWidth < this.LayoutGrid.ActualWidth &&
                bi.PixelHeight < this.LayoutGrid.ActualHeight)
            {
                offsetX = 0.5 * (this.LayoutGrid.ActualWidth - bi.PixelWidth);
                offsetY = 0.5 * (this.LayoutGrid.ActualHeight - bi.PixelHeight);
                //imageScale = 1; - remains
            }
            else if (imageRatio < gridRatio)
            {
                offsetX = 0.5 * (this.LayoutGrid.ActualWidth - imageRatio * this.LayoutGrid.ActualHeight);
                offsetY = 0;
                imageScale = BigImage.ActualHeight / bi.PixelHeight;
            }
            else
            {
                offsetX = 0;
                offsetY = 0.5 * (this.LayoutGrid.ActualHeight - this.LayoutGrid.ActualWidth / imageRatio);
                imageScale = BigImage.ActualWidth / bi.PixelWidth;
            }

            //DV: This is probably not need anymore
           //MagnifierTip.MagnifierTransform.X = this.pointerX;
           //MagnifierTip.MagnifierTransform.Y = this.pointerY;
            MagnifierTip.PositionTransform.X = (-this.pointerX + offsetX) / imageScale;
            MagnifierTip.PositionTransform.Y = (-this.pointerY + offsetY) / imageScale;

            //DV: I haven't tested the Scaling/Zoom
            MagnifierTip.ZoomTransform.ScaleX = imageScale * zoomScale;
            MagnifierTip.ZoomTransform.ScaleY = imageScale * zoomScale;

            MagnifierTip.CenterTransform.X = MagnifierTip.MagnifierEllipse.ActualWidth / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;
            MagnifierTip.CenterTransform.Y = MagnifierTip.MagnifierEllipse.ActualHeight / 2 - MagnifierTip.MagnifierEllipse.StrokeThickness / 2;

            //DV: I added a GlobalGrid Transform which translates every children
            MagnifierTip.MagnifierTransformGrid.X = this.pointerX - (MagnifierTip.ActualWidth / 2);
            MagnifierTip.MagnifierTransformGrid.Y = this.pointerY - (MagnifierTip.ActualHeight); ;

        }

        private void LayoutGrid_OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
        {
            if (e.GetCurrentPoint(this.LayoutGrid).Properties.MouseWheelDelta > 0)
            {
                zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale * 1.2));
            }
            else
            {
                zoomScale = Math.Max(MinZoomScale, Math.Min(MaxZoomScale, zoomScale / 1.2));
            }

            this.UpdateMagnifier();
        }


        //DV: Holding usually only works with touch https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.uielement.holding.aspx?f=255&MSPPError=-2147217396
        private void LayoutGrid_Holding(object sender, HoldingRoutedEventArgs e)
        {
            //
        }

        //DV: pointer pressed supports both mouse and touch but fires immeadiatley. You'll have to figure out a delay strategy or using holding for touch and right click for mouse
        private void LayoutGrid_OnPointerPressed(object sender, PointerRoutedEventArgs e)
        {
            MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Visible;
        }

        //DV: pointer released supports both mouse and touch.
        private void LayoutGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
        {
            MagnifierTip.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
        }
    }
}

Magnifier.xaml

<UserControl
    x:Class="App78.Magnifier"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App78"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Height="230"
    Width="170">


    <Grid Height="230" Width="170">

        <!-- DV: This is the global transform I added -->
        <Grid.RenderTransform>
            <TransformGroup>
                <TranslateTransform x:Name="MagnifierTransformGrid" x:FieldModifier="public"/>
            </TransformGroup>
        </Grid.RenderTransform>
        <Ellipse Opacity="1" Visibility="Visible" Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}"  HorizontalAlignment="Center" VerticalAlignment="Top" IsHitTestVisible="False" Width="135" Height="128"  StrokeThickness="3" Margin="0,17,0,0" />
        <Ellipse x:Name="MagnifierEllipse" x:FieldModifier="public" Opacity="1" Visibility="Visible" HorizontalAlignment="Left" VerticalAlignment="Top" IsHitTestVisible="False" Width="150" Height="150" Stroke="White" StrokeThickness="3" Margin="11,8,0,0" >
            <Ellipse.Fill>
                <ImageBrush
                    ImageSource="http://blog.al.com/space-news/2009/04/iss015e22574.jpg"
                    Stretch="None"
                    AlignmentX="Left"
                    AlignmentY="Top">
                    <ImageBrush.Transform>
                        <TransformGroup>
                            <TranslateTransform x:FieldModifier="public"
                                x:Name="CenterTransform"/>
                            <TranslateTransform x:FieldModifier="public"
                                x:Name="PositionTransform"/>
                            <ScaleTransform x:FieldModifier="public"
                                x:Name="ZoomTransform"/>
                        </TransformGroup>
                    </ImageBrush.Transform>
                </ImageBrush>
            </Ellipse.Fill>
        </Ellipse>
        <Path Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z"
              Fill="#FFF4F4F5"
              Stretch="Fill"
              Stroke="Black"
              UseLayoutRounding="False"
              Height="227"
              Width="171" ></Path>
    </Grid>
</UserControl>