【发布时间】: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