c# - 如何在 Canvas 上旋转动态创建的 ListBoxItem?

标签 c# wpf mvvm listbox rotation

在我的 WPF MVVM 应用程序中,我有一个 ListBoxCanvas作为其 ItemsPanel . ListBox 的项目由用户在单击按钮时动态创建 - ListBox.ItemsSource是存储在我的 MainViewModel 中的自定义类型的项目列表这是 DataContext我的MainWindow .我希望用户能够使用一组 Thumb 来旋转项目控件附加到每个 ListBoxItem .到目前为止,我在尝试找到可行的解决方案时收效甚微,我变得非常绝望。

这是我的 ListBoxItem 中最重要的部分的风格:

<Style TargetType="ListBoxItem">
  <Setter Property="Canvas.Left" Value="{Binding X}"/>
  <Setter Property="Canvas.Top" Value="{Binding Y}"/>
  <Setter Property="Width" Value="{Binding Width}"/>
  <Setter Property="Height" Value="{Binding Height}"/>
  <Setter Property="FocusVisualStyle" Value="{StaticResource EmptyFocusVisualStyle}"/>
    <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="ListBoxItem" >
             <Grid>
                <Control Name="RotateDecorator"   
                         Width="{Binding Width}" Height="{Binding Height}"
                         Template="{StaticResource RotateDecoratorTemplate}"
                         Visibility="Visible"/>
                          <ContentPresenter x:Name="Content" />
             </Grid>
         </ControlTemplate>
      </Setter.Value>
  </Setter>

在这里你可以看到它的样子:http://screenshooter.net/100101493/dhokpue

RotateDecorator本质上只是一组稍微定制的 Thumb我想旋转 ListBoxItem 的控件(在图片中显示为所选项目周围的小三角形) .但是我完全没有关于如何做到这一点的想法。我唯一知道的是我需要写合适的 DragDeltaDragStarted作为事件处理程序的方法。有什么想法可以缓解我的愤怒吗?

编辑:这里是 DragStartedDragDelta RotationThumb 的方法.它们会影响移动 Thumb 的行为方式吗?

开始拖动:

private void RotateThumb_DragStarted(object sender, DragStartedEventArgs e)
    {
        var thumb = sender as RotateThumb;
        var parent = VisualTreeHelper.GetParent(thumb);
        for (int i = 0; i < 3; i++ )
        {
            parent = VisualTreeHelper.GetParent(parent);
        }
        this.designerItem = parent as ListBoxItem;

        if (this.designerItem != null)
        {
            this.designerCanvas = VisualTreeHelper.GetParent(this.designerItem) as Canvas;

            if (this.designerCanvas != null)
            {
                this.centerPoint = this.designerItem.TranslatePoint(
                    new Point(this.designerItem.Width * this.designerItem.RenderTransformOrigin.X,
                              this.designerItem.Height * this.designerItem.RenderTransformOrigin.Y),
                              this.designerCanvas);

                Point startPoint = Mouse.GetPosition(this.designerCanvas);
                this.startVector = Point.Subtract(startPoint, this.centerPoint);

                this.rotateTransform = this.designerItem.RenderTransform as RotateTransform;
                if (this.rotateTransform == null)
                {
                    this.designerItem.RenderTransform = new RotateTransform(0);
                    this.initialAngle = 0;
                }
                else
                {
                        this.initialAngle = this.rotateTransform.Angle;
                }
            }
        }
    }

拖动增量:

private void RotateThumb_DragDelta(object sender, DragDeltaEventArgs e)
    {
        if (this.designerItem != null && this.designerCanvas != null)
        {
            Point currentPoint = Mouse.GetPosition(this.designerCanvas);
            Vector deltaVector = Point.Subtract(currentPoint, this.centerPoint);

            double angle = Vector.AngleBetween(this.startVector, deltaVector);

            RotateTransform rotateTransform = this.designerItem.RenderTransform as RotateTransform;
            rotateTransform.Angle = this.initialAngle + Math.Round(angle, 0);
            this.designerItem.InvalidateMeasure();
        }
    }

EDIT2:问题已解决

最佳答案

有几种方法,但这里有一些伪代码可以帮助您入门:

// for every drag event
Point a = listboxitem center position (or wherever you want the rotation origin)
Point b = position before drag
Point c = position after drag

// calculate and normalize vectors a-b and a-c
Vector v1 = ( b - a ).Normalized();
Vector v2 = ( c - a ).Normalized();

// calculate angles for v1 and v2 (in radians)
double a1 = Math.Atan2( v1.y, v1.x );
double a2 = Math.Atan2( v2.y, v2.x );

// the amount of rotation is then the difference between a1 and a2
// NOTE: there's a catch here, Atan2 returns angles = -π ≤ θ ≤ π, so
// the values might wrap around, which you'll need to take care of too
double angleInRadians = a2 - a1;
double angleInDegrees = ( angleInRadians / Math.PI ) * 180.0;

然后将这个角度添加到您放置在 ListBoxItem 上的 RotateTransform 的角度。

关于c# - 如何在 Canvas 上旋转动态创建的 ListBoxItem?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24970720/

相关文章:

wpf - 自定义 WPF 窗口样式

.net - 使用 MVVM 处理 WPF 中的对话框

c# - 将图像转换为字节数组

c# - 如何为给定类型创建实例?

.net - 如何在 WPF 中检测鼠标双击左键?

c# - Storyboard运行导致不透明度消失后,无法将边框不透明度重置为 1.0

c# - 通过 MVVM 模式创建 UserControl - DataContext 并绑定(bind)到父级

c# - 绑定(bind)到第二个属性

c# - 系统.BadImageFormatException : Could not load file or assembly 'x_Accessor,...' This assembly is built by a runtime newer

C#:创建图形屏幕保护程序