WPF旋转板栈设计一例

效果图

项目中需要做一个机台的平面视图,点击其中一个料盒时,弹出该料盒的料管列表,用WPF示例做了一下,效果如下:

用户控件XAML

复制代码
 1 <UserControl x:Class="WpfApp1.Views.BoardStackControl"
 2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
 5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
 6              xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
 7              xmlns:local="clr-namespace:WpfApp1.Views"
 8              xmlns:wpfapp1="clr-namespace:WpfApp1"
 9              d:DataContext="{d:DesignInstance Type=wpfapp1:MainViewModel}"
10              Width="224" Height="300"
11              mc:Ignorable="d" 
12              d:DesignHeight="300" d:DesignWidth="250">
13     <UserControl.DataContext>
14         <wpfapp1:MainViewModel />
15     </UserControl.DataContext>
16     <Grid>
17         <!--<ItemsControl ItemsSource="{Binding NestGroups}">
18             <ItemsControl.ItemsPanel>
19                 <ItemsPanelTemplate>
20                     <StackPanel Orientation="Horizontal"></StackPanel>
21                 </ItemsPanelTemplate>
22             </ItemsControl.ItemsPanel>
23             <ItemsControl.ItemTemplate>
24                 <DataTemplate>-->
25         <Border Margin="1">
26             <Grid Width="220" Height="220">
27                 <Ellipse Stroke="#dcdfe3" StrokeThickness="3"  Width="220" Height="220"/>
28                 <Ellipse Stroke="#dcdfe3" StrokeThickness="3"  Width="80" Height="80" HorizontalAlignment="Center" VerticalAlignment="Center"/>
29                 <ItemsControl ItemsSource="{Binding LeftTubes3}">
30                     <ItemsControl.ItemsPanel>
31                         <ItemsPanelTemplate>
32                             <Canvas/>
33                         </ItemsPanelTemplate>
34                     </ItemsControl.ItemsPanel>
35                     <ItemsControl.ItemContainerStyle>
36                         <Style TargetType="ContentPresenter">
37                             <Setter Property="Canvas.Left"  Value="{Binding X, Mode=OneWay}"/>
38                             <Setter Property="Canvas.Top"  Value="{Binding Y, Mode=OneWay}"/>
39                             <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
40                             <Setter Property="RenderTransform">
41                                 <Setter.Value>
42                                     <RotateTransform Angle="{Binding Angle}"/>
43                                 </Setter.Value>
44                             </Setter>
45                         </Style>
46                     </ItemsControl.ItemContainerStyle>
47                     <ItemsControl.ItemTemplate>
48                         <DataTemplate>
49                             <Grid>
50                                 <Border Width="35" Height="50" Tag="{Binding .}" x:Name="animatedBorder" MouseLeftButtonDown="Border_MouseLeftButtonDown" 
51                         CornerRadius="3"  Background="#FFE6E6E6" BorderBrush="Gray" BorderThickness="1">
52                                     <ItemsControl ItemsSource="{Binding Tubes}" Margin="2" IsHitTestVisible="False">
53                                         <ItemsControl.ItemsPanel>
54                                             <ItemsPanelTemplate>
55                                                 <UniformGrid Columns="{Binding Rows}" Rows="{Binding Cols}" IsHitTestVisible="False"/>
56                                             </ItemsPanelTemplate>
57                                         </ItemsControl.ItemsPanel>
58                                         <ItemsControl.ItemTemplate>
59                                             <DataTemplate>
60                                                 <Ellipse Width="{Binding Width}" Height="{Binding Height}" Fill="#FF4F81BD"  Margin="{Binding Margin}" Stroke="Black" StrokeThickness="0.5" IsHitTestVisible="False"/>
61                                             </DataTemplate>
62                                         </ItemsControl.ItemTemplate>
63                                     </ItemsControl>
64                                     <Border.Triggers>
65                                         <EventTrigger RoutedEvent="MouseLeftButtonUp">
66                                             <BeginStoryboard>
67                                                 <Storyboard>
68                                                     <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="0:0:0.1" AutoReverse="True"/>
69                                                 </Storyboard>
70                                             </BeginStoryboard>
71                                         </EventTrigger>
72                                     </Border.Triggers>
73                                 </Border>
74                                 <Border Width="20" Height="20" CornerRadius="10"  Background="#FF4F81BD" BorderBrush="White" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,-10,0,0">
75                                     <TextBlock Text="{Binding Index}"   Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
76                                 </Border>
77                             </Grid>
78                         </DataTemplate>
79                     </ItemsControl.ItemTemplate>
80                 </ItemsControl>
81             </Grid>
82         </Border>
83         <!--</DataTemplate>
84             </ItemsControl.ItemTemplate>
85         </ItemsControl>-->
86 
87     </Grid>
88 </UserControl>
89 
90     

View Code

用户控件XMAL.CS

复制代码
 1 using CommunityToolkit.Mvvm.Messaging;
 2 using Microsoft.Extensions.Logging;
 3 using System.Collections.ObjectModel;
 4 using System.Diagnostics;
 5 using System.Windows;
 6 using System.Windows.Controls;
 7 using System.Windows.Input;
 8 using System.Windows.Media;
 9 using WpfApp1.Entities;
10 
11 namespace WpfApp1.Views;
12 
13 public partial class BoardStackControl : UserControl
14 {
15     public BoardStackControl()
16     {
17         InitializeComponent();
18 
19     }
20 
21     public static readonly RoutedEvent BorderClickedEvent =
22         EventManager.RegisterRoutedEvent(
23             "BorderClicked",
24             RoutingStrategy.Bubble,
25             typeof(RoutedEventHandler),
26             typeof(BoardStackControl)
27         );
28 
29     public event RoutedEventHandler BorderClicked
30     {
31         add => AddHandler(BorderClickedEvent, value);
32         remove => RemoveHandler(BorderClickedEvent, value);
33     }
34 
35     private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
36     {
37         if (sender is Border border && border.DataContext is BoxPosition boxPosition)
38         {
39             // 触发路由事件,并携带索引
40             var args = new RoutedEventArgs(BorderClickedEvent, boxPosition.Index);
41             RaiseEvent(args);
42             e.Handled = true;
43         }
44     }
45 
46 }

View Code

主窗口XAML

复制代码
 1 <Window x:Class="WpfApp1.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:WpfApp1"
 7         xmlns:view="clr-namespace:WpfApp1.Views"
 8         mc:Ignorable="d"
 9         Title="MainWindow" Height="450" Width="800">
10     <Window.DataContext>
11         <local:MainViewModel />
12     </Window.DataContext>
13     <Grid>
14         <Border BorderBrush="Gray" BorderThickness="1">
15             <Grid>
16                 <Grid.RowDefinitions>
17                     <RowDefinition Height="100"/>
18                     <RowDefinition Height="300"/>
19                 </Grid.RowDefinitions>
20                 <Grid.ColumnDefinitions>
21                     <ColumnDefinition Width="*"></ColumnDefinition>
22                     <ColumnDefinition Width="*"></ColumnDefinition>
23                     <ColumnDefinition Width="*"></ColumnDefinition>
24                 </Grid.ColumnDefinitions>
25 
26                 <Border Grid.ColumnSpan="3" Grid.Row="0"  BorderBrush="LightGray" BorderThickness="0,0,0,1">
27                     <Grid>
28                         <Rectangle Fill="#FFD3D3D3" Height="60" VerticalAlignment="Center"/>
29 
30                         <Path Data="M117 91q-6-7 1-12l2-26q-3-1-2-7L85 34q-3 4-8 1L54 48q0 4-5 5L48 54 38 61l-1-1 10-7-3-3-10 6-1-1 10-6 1-1L44 47q1-4 5-4L75 28c2-4 6-5 10-2l40 15q9 0 6 9l2 29q7 5 0 13l14 8v7H101v-7Z" 
31                           Fill="#FF4F81BD" Stroke="Black" StrokeThickness="1"
32                           HorizontalAlignment="Center" VerticalAlignment="Center"
33                           Margin="-20,0,0,0" />
34                     </Grid>
35                 </Border>
36 
37                 <view:BoardStackControl Grid.Row="1" Grid.Column="0" BorderClicked="Rack1Control_BorderClicked" />
38                 <view:BoardStackControl Grid.Row="1" Grid.Column="1" BorderClicked="Rack2Control_BorderClicked" />
39                 <view:BoardStackControl Grid.Row="1" Grid.Column="2" BorderClicked="Rack3Control_BorderClicked" />
40             </Grid>
41         </Border>
42     </Grid>
43 </Window>

View Code

主窗口XAML.CS

复制代码
 1 using System.Diagnostics;
 2 using System.Text;
 3 using System.Windows;
 4 using System.Windows.Controls;
 5 using System.Windows.Data;
 6 using System.Windows.Documents;
 7 using System.Windows.Input;
 8 using System.Windows.Media;
 9 using System.Windows.Media.Imaging;
10 using System.Windows.Navigation;
11 using System.Windows.Shapes;
12 using WpfApp1.Entities;
13 using WpfApp1.Views;
14 
15 namespace WpfApp1
16 {
17     /// <summary>
18     /// Interaction logic for MainWindow.xaml
19     /// </summary>
20     public partial class MainWindow : Window
21     {
22         public MainWindow()
23         {
24             InitializeComponent();
25         }
26 
27         private void Rack1Control_BorderClicked(object sender, RoutedEventArgs e)
28         {
29             if (e.OriginalSource is int index)
30             {
31                 MessageBox.Show($"点击了第 1 个板栈的第 {index} 个 Border");
32                 ExecuteMainWindowMethod(index);
33             }
34         }
35         private void Rack2Control_BorderClicked(object sender, RoutedEventArgs e)
36         {
37             if (e.OriginalSource is int index)
38             {
39                 MessageBox.Show($"点击了第 2 个板栈的第 {index} 个 Border");
40                 ExecuteMainWindowMethod(index);
41             }
42         }
43         private void Rack3Control_BorderClicked(object sender, RoutedEventArgs e)
44         {
45             if (e.OriginalSource is int index)
46             {
47                 MessageBox.Show($"点击了第 3 个板栈的第 {index} 个 Border");
48                 ExecuteMainWindowMethod(index);
49             }
50         }
51 
52         private void ExecuteMainWindowMethod(int index)
53         {
54             //// 这里编写 MainWindow 的具体逻辑
55             //// 例如更新 UI 或处理业务逻辑
56             //var vm = (MainViewModel)this.DataContext;
57             //vm.RackClickedCommand.Execute($"2_{deviceCode}_{rackIndex}");
58         }
59     }
60 }

View Code

主窗口ViewModel

复制代码
  1 using CommunityToolkit.Mvvm.ComponentModel;
  2 using CommunityToolkit.Mvvm.Input;
  3 using CommunityToolkit.Mvvm.Messaging;
  4 using System;
  5 using System.Collections.Generic;
  6 using System.ComponentModel;
  7 using System.Diagnostics;
  8 using System.Runtime.CompilerServices;
  9 using System.Windows.Input;
 10 using WpfApp1.Entities;
 11 using WpfApp1.Views;
 12 
 13 namespace WpfApp1
 14 {
 15     public partial class MainViewModel
 16     {
 17 
 18         public MainViewModel()
 19         {
 20 
 21             LeftTubes3 = CreateCircularTubes(12, 18, 110, 50);
 22 
 23             //IsActive = true;
 24         }
 25 
 26         #region 左侧板栈UI
 27 
 28         public List<BoxPosition> LeftTubes3 { get; set; } = [];
 29 
 30         private static List<BoxPosition> CreateCircularTubes(int count, int tubs, double outerRadius, double innerRadius)
 31         {
 32             var positions = new List<BoxPosition>();
 33             double centerX = outerRadius;
 34             double centerY = outerRadius;
 35 
 36             for (int i = 0; i < count; i++)
 37             {
 38                 // 计算角度 (360度均匀分布)
 39                 double angleDeg = 360.0 * i / count;
 40                 double angleRad = angleDeg * Math.PI / 180.0;
 41 
 42                 // 计算位置 (在内外半径之间)
 43                 double radius = (outerRadius + innerRadius) / 2;
 44                 double x = centerX + radius * Math.Cos(angleRad) - 17; // 25是料盒宽度的一半
 45                 double y = centerY + radius * Math.Sin(angleRad) - 25; // 35是料盒高度的一半
 46 
 47                 // 行数和列数
 48                 var rows = 2;
 49                 var cols = 3;
 50                 var margin = 2;
 51                 var width = 10;
 52                 var height = 10;
 53                 switch (tubs)
 54                 {
 55                     case 3:
 56                         rows = 1;
 57                         cols = 3;
 58                         margin = 2;
 59                         width = 10;
 60                         height = 10;
 61                         break;
 62                     //case 6:
 63                     //    rows = 2;
 64                     //    cols = 3;
 65                     //    break;
 66                     case 12:
 67                         rows = 3;
 68                         cols = 4;
 69                         margin = 1;
 70                         width = 5;
 71                         height = 5;
 72                         break;
 73                     case 18:
 74                         rows = 3;
 75                         cols = 6;
 76                         margin = 1;
 77                         width = 4;
 78                         height = 4;
 79                         break;
 80                     case 96:
 81                         rows = 8;
 82                         cols = 12;
 83                         margin = 0;
 84                         width = 1;
 85                         height = 1;
 86                         break;
 87                 }
 88 
 89                 // 创建6个料管
 90                 var tubes = new List<Tube>();
 91                 for (int j = 0; j < tubs; j++)
 92                 {
 93                     tubes.Add(new Tube
 94                     {
 95                         Margin = margin,
 96                         Width = width,
 97                         Height = height,
 98                     });
 99                 }
100 
101                 positions.Add(new BoxPosition
102                 {
103                     Index = i + 1,
104                     X = x,
105                     Y = y,
106                     Rows = rows,
107                     Cols = cols,
108                     Angle = angleDeg + 90, // 旋转角度等于位置角度
109                     Tubes = tubes
110                 });
111             }
112 
113             return positions;
114         }
115 
116 
117         #endregion
118 
119     }
120 }

View Code

Entities

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace WpfApp1.Entities
 8 {
 9     public class NestGroup
10     {
11         public List<BoxPosition> Nests { get; set; } = [];
12     }
13     public class BoxPosition
14     {
15         public int Index { get; set; }
16         public double X { get; set; }
17         public double Y { get; set; }
18         public double Angle { get; set; }
19         public int Rows { get; set; } = 2;
20         public int Cols { get; set; } = 3;
21         public List<Tube> Tubes { get; set; } = [];
22     }
23 
24     public class Tube
25     {
26         public int Margin { get; set; } = 2;
27         public int Width { get; set; } = 10;
28         public int Height { get; set; } = 10;
29     }
30 }

View Code

相关推荐
WineMonk6 小时前
.NET WPF 可视化树(Visual Tree)
.net·wpf
ALex_zry20 小时前
构建高可靠C++服务框架:从日志系统到任务调度器的完整实现
开发语言·c++·wpf
leslie_xin2 天前
(原创)[开源][.Net Framework 4.5] SimpleMVVM(极简MVVM框架)更新 v1.1,增加NuGet包
c#·wpf
不知名君3 天前
WPF轮播图动画交互 动画缩放展示图片
wpf
Sitarrrr3 天前
【WPF】IOC控制反转的应用:弹窗但不互相调用ViewModel
设计模式·c#·wpf
"孙小浩6 天前
HarmonyOS应用开发者高级-编程题-001
华为·wpf·harmonyos
yngsqq6 天前
003集——《利用 C# 与 AutoCAD API 开发 WPF 随机圆生成插件》(侧栏菜单+WPF窗体和控件+MVVM)
wpf
baivfhpwxf20236 天前
WPF 免费UI 控件HandyControl
ui·wpf
qq_196055876 天前
WPF插入背景图
wpf