【问题标题】:WPF - Path Geometry on Canvas scaling differently than Thumb controlWPF - 画布上的路径几何缩放比例不同于 Thumb 控件
【发布时间】:2023-02-02 01:43:37
【问题描述】:

这是一个 WPF 问题。

我正在尝试使用拇指控件拖动顶点来跟踪/拖动画布上 PathGeometry 的顶点。

似乎 PathGeometry 的缩放比例不同于 Thumb 相对于 Canvas 的位置。

如何计算缩放比例?一旦我有了它,我就可以使用 ScaleTransform 来更正它。

提前致谢。

这是我的 XAML。我有一个硬编码的 3 比例值,但如果我的窗口大小发生变化,它就不起作用:

我的控件.XAML


<UserControl x:Class="WPF_Discovery_Client.ColorOpacityControl"
             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:WPF_Discovery_Client"
             DataContext="{Binding RelativeSource={RelativeSource Self}}"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <Style TargetType="{x:Type Thumb}" x:Key="RoundThumb">
            <Style.Resources>
                <Style TargetType="Border">
                    <Setter Property="CornerRadius" Value="10" />
                    <Setter Property="BorderThickness" Value="1" />
                </Style>
            </Style.Resources>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Canvas Background="aqua" x:Name="MyCanvas" SizeChanged="MyCanvas_SizeChanged" Loaded="MyCanvas_Loaded" >
            <Path Stroke="Black" StrokeThickness="1" Height="450" Stretch="Fill" Width="800" >
                <Path.Fill>
                    <LinearGradientBrush ColorInterpolationMode="ScRgbLinearInterpolation" StartPoint="0,0" EndPoint="1,0">
                        <GradientStop Offset="0" Color="Red"/>
                        <GradientStop Offset="0.17" Color="Orange"/>
                        <GradientStop Offset="0.34" Color="Yellow"/>
                        <GradientStop Offset="0.51" Color="Green"/>
                        <GradientStop Offset="0.68" Color="Blue"/>
                        <GradientStop Offset="0.85" Color="Indigo"/>
                        <GradientStop Offset="1.0" Color="Violet"/>
                    </LinearGradientBrush>
                </Path.Fill>
                <Path.Data>
                    <PathGeometry>
                        <PathGeometry.Figures>
                            <PathFigureCollection>
                                <PathFigure x:Name="MyPath" IsClosed="True" StartPoint="{Binding BottomLeftCorner, Mode=TwoWay}">
                                    <PathFigure.Segments>
                                        <PathSegmentCollection>
                                            <LineSegment Point="{Binding LeftVertex, Mode=TwoWay}"/>
                                            <LineSegment Point="{Binding MiddleVertex, Mode=TwoWay}" />
                                            <LineSegment Point="{Binding RightVertex, Mode=TwoWay}" />
                                            <LineSegment Point="{Binding BottomRightCorner, Mode=TwoWay}" />
                                        </PathSegmentCollection>
                                    </PathFigure.Segments>
                                </PathFigure>
                            </PathFigureCollection>
                        </PathGeometry.Figures>
                    </PathGeometry>
                </Path.Data>
                <Path.RenderTransform>
                    <ScaleTransform ScaleX="2.0" ScaleY="2.0"/>
                </Path.RenderTransform>
            </Path>

            <Thumb Name="LeftThumb" Style="{DynamicResource RoundThumb}" Background="White"
                Width="20" Height="20" DragDelta="LeftThumb_DragDelta" 
                DragStarted="LeftThumb_DragStarted"  DragCompleted="LeftThumb_DragCompleted"/>

            <Thumb Name="MiddleThumb" Style="{DynamicResource RoundThumb}" Background="White"
                Width="20" Height="20" DragDelta="MiddleThumb_DragDelta"
                DragStarted="MiddleThumb_DragStarted"  DragCompleted="MiddleThumb_DragCompleted"/>

            <Thumb Name="RightThumb" Style="{DynamicResource RoundThumb}" Background="White" 
                Width="20" Height="20" DragDelta="RightThumb_DragDelta"
                DragStarted="RightThumb_DragStarted"  DragCompleted="RightThumb_DragCompleted"/>
            
        </Canvas>
    </Grid>
</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.Globalization;
using System.Windows.Controls.Primitives;
using System.ComponentModel;

namespace WPF_Discovery_Client
{
    /// <summary>
    /// Interaction logic for ColorOpacityControl.xaml
    /// </summary>
    public partial class ColorOpacityControl : UserControl, INotifyPropertyChanged
    {
        const int ThumbRadius = 10;

        // Bottom corners
        public Point BottomRightCorner
        {
            get { return (Point)GetValue(BottomRightCornerProperty); }
            set { SetValue(BottomRightCornerProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BottomRightCorner.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BottomRightCornerProperty =
            DependencyProperty.Register("BottomRightCorner", typeof(Point), typeof(ColorOpacityControl), new PropertyMetadata(new Point(0, 100)));



        public Point BottomLeftCorner
        {
            get { return (Point)GetValue(BottomLeftCornerProperty); }
            set { SetValue(BottomLeftCornerProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BottomLeftCorner.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BottomLeftCornerProperty =
            DependencyProperty.Register("BottomLeftCorner", typeof(Point), typeof(ColorOpacityControl), new PropertyMetadata(new Point(0, 200)));


        // Thumb center locations
        public Point LeftVertex
        {
            get { return (Point)GetValue(LeftVertexProperty); }
            set { SetValue(LeftVertexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LeftVertex.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LeftVertexProperty =
            DependencyProperty.Register("LeftVertex", typeof(Point), typeof(ColorOpacityControl), new PropertyMetadata(new Point(0,266)));



        public Point MiddleVertex
        {
            get { return (Point)GetValue(MiddleVertexProperty); }
            set { SetValue(MiddleVertexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MiddleVertex.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MiddleVertexProperty =
            DependencyProperty.Register("MiddleVertex", typeof(Point), typeof(ColorOpacityControl), new PropertyMetadata(new Point(100, 100)));




        public Point RightVertex
        {
            get { return (Point)GetValue(RightVertexProperty); }
            set { SetValue(RightVertexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RightVertex.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RightVertexProperty =
            DependencyProperty.Register("RightVertex", typeof(Point), typeof(ColorOpacityControl), new PropertyMetadata(new Point(100, 50)));




        public ColorOpacityControl()
        {
            InitializeComponent();

            DataContext = this;
        }

        private void LeftThumb_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            LeftThumb.Background = Brushes.Red;
        }

        private void LeftThumb_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            LeftThumb.Background = Brushes.White;
        }

        private void LeftThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            //Move the Thumb to the mouse position during the drag operation
            var yadjust = MyCanvas.ActualHeight + e.VerticalChange;
            var xadjust = MyCanvas.ActualWidth + e.HorizontalChange;
            if ((xadjust >= 0) && (yadjust >= 0))
            {
                // Compute new thumb location
                double X = Canvas.GetLeft(LeftThumb) + e.HorizontalChange;
                double Y = Canvas.GetTop(LeftThumb) + e.VerticalChange;

                // Move thumb
                Canvas.SetLeft(LeftThumb, X);
                Canvas.SetTop(LeftThumb, Y);

                // Compute center of thumb as vertex location
                LeftVertex = new Point(X + LeftThumb.Width, Y + LeftThumb.Height);
                NotifyPropertyChanged("LeftVertex");
            }
        }

        private void MiddleThumb_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            MiddleThumb.Background = Brushes.Green;
        }

        private void MiddleThumb_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            MiddleThumb.Background = Brushes.White;
        }

        private void MiddleThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            //Move the Thumb to the mouse position during the drag operation
            var yadjust = MyCanvas.ActualHeight + e.VerticalChange;
            var xadjust = MyCanvas.ActualWidth + e.HorizontalChange;
            if ((xadjust >= 0) && (yadjust >= 0))
            {
                // Compute new thumb location
                double X = Canvas.GetLeft(MiddleThumb) + e.HorizontalChange;
                double Y = Canvas.GetTop(MiddleThumb) + e.VerticalChange;

                // Move thumb
                Canvas.SetLeft(MiddleThumb, X);
                Canvas.SetTop(MiddleThumb, Y);

                // Compute center of thumb as vertex location
                MiddleVertex = new Point(X + MiddleThumb.Width, Y + MiddleThumb.Height);
                NotifyPropertyChanged("MiddleVertex");
            }
        }

        private void RightThumb_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            RightThumb.Background = Brushes.Yellow;
        }

        private void RightThumb_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            RightThumb.Background = Brushes.White;
        }

        private void RightThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            //Move the Thumb to the mouse position during the drag operation
            var yadjust = MyCanvas.ActualHeight + e.VerticalChange;
            var xadjust = MyCanvas.ActualWidth + e.HorizontalChange;
            if ((xadjust >= 0) && (yadjust >= 0))
            {
                // Compute new thumb location
                double X = Canvas.GetLeft(RightThumb) + e.HorizontalChange;
                double Y = Canvas.GetTop(RightThumb) + e.VerticalChange;

                // Move thumb
                Canvas.SetLeft(RightThumb, X);
                Canvas.SetTop(RightThumb, Y);

                // Compute center of thumb as vertex location
                RightVertex = new Point(X + ThumbRadius, Y + ThumbRadius);
                NotifyPropertyChanged("RightVertex");
            }
        }

        private void MyCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            // Adjust bottom left corners
            BottomLeftCorner = new Point(0, MyCanvas.ActualHeight);
            NotifyPropertyChanged("BottomLeftCorner");

            // Adjust botton right corner
            BottomRightCorner = new Point(MyCanvas.ActualWidth, MyCanvas.ActualHeight);
            NotifyPropertyChanged("BottomRightCorner");
        }

        private void InitializeVertices()
        {
            // Initialize bottom left corner
            BottomLeftCorner = new Point(ThumbRadius, MyCanvas.ActualHeight - ThumbRadius);
            NotifyPropertyChanged("BottomLeftCorner");

            // Initialize bottom right corner
            BottomRightCorner = new Point(MyCanvas.ActualWidth - ThumbRadius, MyCanvas.ActualHeight - ThumbRadius);
            NotifyPropertyChanged("BottomRightCorner");

            // Initialize right vertex
            RightVertex = new Point(MyCanvas.ActualWidth - ThumbRadius, ThumbRadius);
            NotifyPropertyChanged("RightVertex");

            // Initialize left vertex
            LeftVertex = BottomLeftCorner;
            NotifyPropertyChanged("LeftVertex");

            // Initialize middle vertex
            MiddleVertex = new Point(MyCanvas.ActualWidth * 0.5, MyCanvas.ActualHeight * 0.5);
            NotifyPropertyChanged("MiddleVertex");

            // Initialize Left Thumb
            Canvas.SetLeft(LeftThumb, LeftVertex.X - ThumbRadius);
            Canvas.SetTop(LeftThumb, LeftVertex.Y - ThumbRadius);

            // Initialize Right Thumb
            Canvas.SetLeft(RightThumb, RightVertex.X - ThumbRadius);
            Canvas.SetTop(RightThumb, RightVertex.Y - ThumbRadius);

            // Initialize Middle Thumb
            Canvas.SetLeft(MiddleThumb, MiddleVertex.X - ThumbRadius);
            Canvas.SetTop(MiddleThumb, MiddleVertex.Y - ThumbRadius);
        }


        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }


        #endregion

        private void MyCanvas_Loaded(object sender, RoutedEventArgs e)
        {
            InitializeVertices();
        }

    }
}

如您所见,我将顶点和拇指设置为相对于画布的相同位置。但是,如果您运行代码,您会看到带有渐变填充的初始三角形比需要的小得多。我希望 3 个拇指与 2 个顶点和中点重合。

此外,我注意到我为路径指定了高度和宽度,我不确定是否需要。如果我把它变大以匹配画布的大小,三角形就会变大。我应该将 Height 和 with 设置为 * 吗?

我是 WPF 图形的新手,所以任何帮助将不胜感激。

【问题讨论】:

  • 请不要让我们猜测您的代码应该做什么。对其进行解释,并解释观察到的行为与您的预期有何不同。
  • 正如克莱门斯指出的那样。说出你想做什么并不容易。将固定大小的画布放入视图框中可能值得考虑。或者它可能不会。
  • 我正在尝试创建一个可调整大小的控件,它允许我拖动 3 个拇指来移动 3 个顶点。由于某种原因,拇指没有与 3 个顶点对齐,即使我将它们设置为与拇指相同的值。如果您想尝试构建并使用它,我已经包含了该控件的完整源代码。只需运行它并尝试拖动 3 个白点。然后你会看到我想做什么。再次感谢 :)

标签: wpf canvas scaletransform


【解决方案1】:

好吧..在我的头撞墙几天之后,我终于想出了解决这个问题的方法。希望这会为某人节省很多时间和麻烦。

问题是我将路径宽度/高度设置为父窗口的大小,并将 Stretch 属性设置为 Fill。

进行以下更改后,缩放比例就正确了。


    <Canvas Background="Black" x:Name="MyCanvas" SizeChanged="MyCanvas_SizeChanged" Loaded="MyCanvas_Loaded">
        <Path x:Name="MyPath" Stroke="Black" StrokeThickness="1" Height="{Binding MyCanvas.ActualHeight}" Width="{Binding MyCanvas.ActualWidth}" Stretch="None"  HorizontalAlignment="Left" VerticalAlignment="Top">

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多