WPF 实现冒泡排序可视化
实现冒泡排序代码就不过多讲解,主要是实现动画效果思路,本demo使用MVVM模式编写,读者可自行参考部分核心代码,即可实现如视频所示效果。
对于新手了解算法相关知识应该有些许帮助,至于其它类型排序,也可按该思路自行修改实现。
直接上代码,页面布局.xaml代码如下:
<UserControl x:Class="Wpf_MetroListBox.Views.Test.CanvasLabelMove"
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_MetroListBox.Views.Test"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="380"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Canvas x:Name="canvas" Grid.Row="0" Background="White">
</Canvas>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="创建序列" HorizontalAlignment="Center" Grid.Column="0" Width="70" Height="35" Command="{Binding CommitCommand}" Style="{DynamicResource btn-info-m}"></Button>
<Button Content="执行排序" HorizontalAlignment="Center" Grid.Column="1" Width="70" Height="35" Command="{Binding QueryCommand}" Style="{DynamicResource btn-info-m}"></Button>
</Grid>
</Grid>
</UserControl>
逻辑代码实现如下:
public partial class CanvasLabelMove : UserControl
{
CanvasLabelMoveViewModel vm;
private Random random = new Random();
private List<Label> labels = new List<Label>();
private int[] array;
private int delay = 1000; // 动画延迟时间(毫秒)
public CanvasLabelMove()
{
InitializeComponent();
vm = new CanvasLabelMoveViewModel();
this.DataContext = vm;
this.Publish(EventNames.MainWindowLoadControlEvent, "排序可视化");
this.Subscriber<string>(EventNames.DataGridFocusChangedEvent, async contentStr =>
{
if (contentStr.Equals("1"))
{
InitializeArrayAndLabels();
}
else if (contentStr.Equals("2"))
{
StartBubbleSortAnimation();
}
});
}
private void InitializeArrayAndLabels()
{
int size = 18; // 数组大小 控制标签个数
array = new int[size];
labels.Clear();
canvas.Children.Clear();
HashSet<int> randomNumbers = new HashSet<int>();
Random random = new Random();
//生成不重复随机数
while (randomNumbers.Count < size)
{
int nextNumber = random.Next(22, 200);
randomNumbers.Add(nextNumber);
}
int j = 0;
foreach (int number in randomNumbers)
{
array[j] = number;
j++;
}
for (int i = 0; i < size; i++)
{
Label label = new Label
{
Content = array[i].ToString(),
FontSize = 12,
Width = 35,
Height = array[i],
Margin = new Thickness(50, 0, 0, 0),
Foreground = Brushes.Black,
Background = Brushes.BlanchedAlmond,
VerticalContentAlignment = VerticalAlignment.Center,
HorizontalContentAlignment = HorizontalAlignment.Center
};
Canvas.SetLeft(label, i * 50); // 设置Label的X坐标
Canvas.SetBottom(label, (canvas.ActualHeight / 2) - 100); // 设置Label的Y坐标在中间
canvas.Children.Add(label);
labels.Add(label);
}
}
private async void StartBubbleSortAnimation()
{
for (int j = 0; j <= array.Length - 1; j++)
{
for (int i = 0; i <= array.Length - 2; i++)
{
if (array[i] > array[i + 1])
{
Swap(i, i + 1);
// 更新Label位置
AnimateSwap(i, i + 1);
await Task.Delay(delay);
}
}
}
}
private void Swap(int i, int j)
{
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
private async void AnimateSwap(int i, int j)
{
// 临时存储Label的位置
double label1X = Canvas.GetLeft(labels[i]);
double label2X = Canvas.GetLeft(labels[j]);
await Task.Delay(delay / 10); // 控制动画速度
var animation1 = new DoubleAnimation(label2X, TimeSpan.FromSeconds(0.5));
var animation2 = new DoubleAnimation(label1X, TimeSpan.FromSeconds(0.5));
labels[i].BeginAnimation(Canvas.LeftProperty, animation1);
labels[j].BeginAnimation(Canvas.LeftProperty, animation2);
// 最终位置
//Canvas.SetLeft(labels[i], label2X);
//Canvas.SetLeft(labels[j], label1X);
Label tempLabel = labels[i];
labels[i] = labels[j];
labels[j] = tempLabel;
}
}
public class CanvasLabelMoveViewModel : BaseValidViewModel
{
public CanvasLabelMoveViewModel()
{
}
protected override void ExecuteCommitCommand()
{
this.Publish(EventNames.DataGridFocusChangedEvent, "1");
}
protected override void ExecuteQueryCommand()
{
this.Publish(EventNames.DataGridFocusChangedEvent, "2");
}
}