XML
<UserControl x:Class="WpfControlStone.StoneCoke"
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:WpfControlStone"
mc:Ignorable="d"
IsHitTestVisible="False"
>
<Viewbox Stretch="Uniform">
<Grid Width="300" Height="300">
<Canvas x:Name="MainCanvas" Background="{Binding BackgroundColor, RelativeSource={RelativeSource AncestorType=UserControl}}">
</Canvas>
</Grid>
</Viewbox>
</UserControl>
cpp
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.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace WpfControlStone
{
// 自定义用户控件:模拟石头落入瓶子的动画效果
public partial class StoneCoke : UserControl
{
private StoneCoke wpfControl;
private const int MaxActiveRocks = 200;
//降低形状复杂度(减少渲染计算量)
private const int MinRockSize = 4;
private const int MaxRockSize = 10;
// 随机数生成器:用于生成石头的随机位置、大小、形状等
private Random random = new Random();
// 每秒生成的石头数量(初始值)
private int rocksPerSecond = 500;
// 初始石头数量(瓶子底部的基础石头)
private const int InitialRockCount = 1000;
// 瓶子宽度
private const double BottleWidth = 200;
// 瓶子高度
private const double BottleHeight = 400;
// 瓶子顶部Y坐标
private const double BottleTop = 100;
// 石头堆积表面的Y坐标(瓶内石头堆积的高度)
private const double RockSurfaceY = 350;
// 石头消失的高度(超过此高度的石头会被移除)
private const double DisappearHeight = 300;
// 当前正在下落的石头集合
private List<FrameworkElement> currentRocks = new List<FrameworkElement>();
// 之前的石头集合(备用)
private List<FrameworkElement> previousRocks = new List<FrameworkElement>();
// 石头生成定时器:控制石头生成的频率
private DispatcherTimer rockGeneratorTimer;
// 额外生成定时器:辅助生成石头,增加生成量
private DispatcherTimer additionalTimer;
private DateTime rockTimerStartTime; // 主生成定时器启动时间
private DateTime additionalTimerStartTime; // 额外生成定时器启动时间
//层级
public static readonly DependencyProperty ZIndexProperty =
DependencyProperty.Register(
"ZIndex",typeof(int),typeof(StoneCoke),new PropertyMetadata(-1, OnZIndexChanged)); // 默认值-1(最下层)
// 2. Z-Index属性访问器(WinCC可直接读写)
public int ZIndex
{
get => (int)GetValue(ZIndexProperty);
set => SetValue(ZIndexProperty, value);
}
// 3. Z-Index变更时,同步更新控件层级
private static void OnZIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is StoneCoke control && e.NewValue is int newZIndex)
{
// 更新当前控件的Z-Index
Panel.SetZIndex(control, newZIndex);
// 同时更新内部画布的Z-Index,确保动画元素层级一致
if (control.MainCanvas != null)
{
Panel.SetZIndex(control.MainCanvas, newZIndex);
}
}
}
// 依赖属性:每秒生成石头数量(允许XAML绑定)
public static readonly DependencyProperty RocksPerSecondProperty =
DependencyProperty.Register("RocksPerSecond", typeof(int), typeof(StoneCoke),
new PropertyMetadata(200, OnRocksPerSecondChanged));
// 依赖属性:是否正在生成石头(允许XAML绑定)
public static readonly DependencyProperty IsGeneratingProperty =
DependencyProperty.Register("IsGenerating", typeof(bool), typeof(StoneCoke),
new PropertyMetadata(true, OnIsGeneratingChanged));
//依赖属性:控制动画开始/结束
public static readonly DependencyProperty IsAnimationRunningProperty =
DependencyProperty.Register("IsAnimationRunning", typeof(bool), typeof(StoneCoke), new PropertyMetadata(false, OnIsAnimationRunningChanged));
// 依赖属性访问器
public bool IsAnimationRunning
{
get => (bool)GetValue(IsAnimationRunningProperty);
set => SetValue(IsAnimationRunningProperty, value);
}
// 依赖属性值变化时触发动画控制
private static void OnIsAnimationRunningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is StoneCoke control && e.NewValue is bool isRunning)
{
// 根据属性值启动或停止动画
if (isRunning)
{
control.StartAnimation();
}
else
{
control.StopAnimation();
}
}
}
//Wincc控制开始
public void StartAnimation()
{
// 1. 先重置动画状态(清除残留石头,恢复初始状态)
ResetAnimation();
// 2. 重置生成状态标记
IsGenerating = true;
// 3. 重新启动生成定时器(如果已存在则先停止)
if (rockGeneratorTimer != null)
{
rockGeneratorTimer.Stop();
}
if (additionalTimer != null)
{
additionalTimer.Stop();
}
// 4. 重新初始化并启动生成逻辑(复用现有方法)
StartRockGenerator();
StartAdditionalGenerator();
}
//WinCC控制结束
public void StopAnimation()
{
// 1. 停止所有定时器,终止新石头生成
rockGeneratorTimer?.Stop();
additionalTimer?.Stop();
// 2. 标记生成状态为停止
IsGenerating = false;
// 3. 停止所有正在进行的动画(可选:根据需求决定是否保留已下落的石头)
//StopAllRockAnimations();
}
// 改变背景色(允许WinCC设置)
public static readonly DependencyProperty BackgroundColorProperty =
DependencyProperty.Register("BackgroundColor", typeof(Color), typeof(StoneCoke),
new PropertyMetadata(Colors.Transparent, OnBackgroundColorChanged));
// 背景颜色属性访问器
public Color BackgroundColor
{
get => (Color)GetValue(BackgroundColorProperty);
set => SetValue(BackgroundColorProperty, value);
}
// 背景颜色变更时更新控件背景
private static void OnBackgroundColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is StoneCoke control && e.NewValue is Color color)
{
control.MainCanvas.Background = new SolidColorBrush(color);
}
}
// 焦炭主色依赖属性(WinCC设置)
public static readonly DependencyProperty CokeMainColorProperty =
DependencyProperty.Register("CokeMainColor", typeof(Color), typeof(StoneCoke),
new PropertyMetadata(Color.FromRgb(150, 30, 30))); // 默认深灰色
// 焦炭高光色依赖属性(用于渐变效果)
public static readonly DependencyProperty CokeHighlightColorProperty =
DependencyProperty.Register("CokeHighlightColor", typeof(Color), typeof(StoneCoke),
new PropertyMetadata(Color.FromRgb(220, 80, 80))); // 默认浅灰色
// 属性访问器
public Color CokeMainColor
{
get => (Color)GetValue(CokeMainColorProperty);
set => SetValue(CokeMainColorProperty, value);
}
public Color CokeHighlightColor
{
get => (Color)GetValue(CokeHighlightColorProperty);
set => SetValue(CokeHighlightColorProperty, value);
}
private void StopAllRockAnimations()
{
foreach (var rock in currentRocks.ToList())
{
// 停止石头的所有动画(位置、旋转、透明度等)
rock.BeginAnimation(Canvas.LeftProperty, null);
rock.BeginAnimation(Canvas.TopProperty, null);
rock.BeginAnimation(OpacityProperty, null);
if (rock.RenderTransform is RotateTransform rotate)
{
rotate.BeginAnimation(RotateTransform.AngleProperty, null);
}
// 可选:将石头固定在当前位置(不删除)
// 若需要清除所有石头,可调用RemoveRock(rock);
}
}
// 每秒生成石头数量的属性访问器
public int RocksPerSecond
{
get => (int)GetValue(RocksPerSecondProperty);
set => SetValue(RocksPerSecondProperty, value);
}
// 是否正在生成石头的属性访问器
public bool IsGenerating
{
get => (bool)GetValue(IsGeneratingProperty);
set => SetValue(IsGeneratingProperty, value);
}
// 构造函数
public StoneCoke()
{
InitializeComponent(); // 初始化控件(由XAML自动生成)
Loaded += OnLoaded; // 绑定控件加载完成事件
}
// 让WPF控件置于底层
// 控件加载完成事件处理:初始化动画
private void OnLoaded(object sender, RoutedEventArgs e)
{
InitializeAnimation(); // 初始化动画相关资源
}
// 键盘按键按下事件处理:响应用户键盘操作
// 初始化动画:绘制瓶子、初始石头并启动生成器
private void InitializeAnimation()
{
//DrawCylinderBottle(); // 绘制瓶子形状
//InitializeBottleRocks(); // 初始化瓶内基础石头
StartRockGenerator(); // 启动石头生成定时器
StartAdditionalGenerator(); // 启动额外生成定时器
}
// 创建随机形状的石头(多边形/椭圆/圆角矩形)
private FrameworkElement CreateRockShape()
{
double size = random.Next(MinRockSize, MaxRockSize);
int shapeType = random.Next(2); // 随机形状类型(0-2)
FrameworkElement rock = null;
// 根据随机类型创建不同形状的石头
switch (shapeType)
{
case 0:
rock = CreateIrregularPolygon(size); // 不规则多边形
break;
case 1:
rock = CreateEllipseRock(size); // 椭圆形
break;
}
// 设置石头的基本尺寸和初始透明度
rock.Width = size;
rock.Height = size;
rock.Opacity = 0; // 初始透明(后续通过动画显示)
rock.IsHitTestVisible = false; // 不需要交互,关闭命中测试
rock.SnapsToDevicePixels = true; // 减少抗锯齿计算
return rock;
}
// 创建不规则多边形石头
private Polygon CreateIrregularPolygon(double size)
{
Polygon polygon = new Polygon();
polygon.Fill = new SolidColorBrush(CokeMainColor);
polygon.Stroke = Brushes.Transparent; // 移除描边
polygon.StrokeThickness = 0;
PointCollection points = new PointCollection();
int sides = random.Next(5, 8); // 随机边数(5-7条边)
double centerX = size / 2; // 中心点X坐标
double centerY = size / 2; // 中心点Y坐标
// 生成多边形的每个顶点
for (int i = 0; i < sides; i++)
{
double angle = 2 * Math.PI * i / sides; // 角度(弧度)
// 随机半径(使形状不规则)
double radius = size / 2 * (0.6 + random.NextDouble() * 0.8);
// 计算顶点坐标(极坐标转直角坐标)
double x = centerX + radius * Math.Cos(angle);
double y = centerY + radius * Math.Sin(angle);
points.Add(new Point(x, y));
}
polygon.Points = points; // 设置顶点集合
return polygon;
}
// 创建椭圆形石头
private Ellipse CreateEllipseRock(double size)
{
Ellipse ellipse = new Ellipse
{
// 随机宽高比例(使椭圆更自然)
Width = size * (0.8 + random.NextDouble() * 0.4),
Height = size * (0.7 + random.NextDouble() * 0.6),
// 填充:径向渐变(中心亮边缘暗)
//Fill = new RadialGradientBrush(
// CokeMainColor,
// CokeHighlightColor),
//Stroke = Brushes.DarkRed, // 描边颜色
//StrokeThickness = 0.8 // 描边厚度
Fill = new SolidColorBrush(CokeMainColor), // 纯色填充
Stroke = Brushes.Transparent,
StrokeThickness = 0
};
return ellipse;
}
// 创建圆角矩形石头
private Rectangle CreateRoundedRock(double size)
{
Rectangle rectangle = new Rectangle
{
// 随机宽高比例
Width = size * (0.7 + random.NextDouble() * 0.6),
Height = size * (0.6 + random.NextDouble() * 0.8),
// 填充:45度角的线性渐变
Fill = new LinearGradientBrush(
CokeMainColor,
CokeHighlightColor,
45),
Stroke = Brushes.DarkRed, // 描边颜色
StrokeThickness = 0.8, // 描边厚度
RadiusX = size * 0.3, // X方向圆角半径
RadiusY = size * 0.2 // Y方向圆角半径
};
return rectangle;
}
// 启动石头生成定时器
private void StartRockGenerator()
{
// 若已有定时器,先停止并释放
if (rockGeneratorTimer != null)
{
rockGeneratorTimer.Stop();
rockGeneratorTimer.Tick -= RockGeneratorTimer_Tick; // 解绑旧事件
}
rockGeneratorTimer = new DispatcherTimer(); // 创建定时器
UpdateTimerInterval(); // 设置定时器间隔(根据生成速度)
rockGeneratorTimer.Tick += RockGeneratorTimer_Tick;
// 延迟1.5秒启动主定时器
DispatcherTimer delayTimer = new DispatcherTimer();
delayTimer.Interval = TimeSpan.FromSeconds(0.5);
delayTimer.Tick += (s, e) =>
{
delayTimer.Stop(); // 关闭延迟定时器(只执行一次)
rockTimerStartTime = DateTime.Now; // 记录主定时器启动时间
rockGeneratorTimer.Start(); // 启动主生成定时器
};
delayTimer.Start();
}
// 提取Tick事件为单独方法(避免匿名委托导致的重复执行问题)
private void RockGeneratorTimer_Tick(object sender, EventArgs e)
{
// 如果当前石头数量已达上限,暂停生成
if (currentRocks.Count >= MaxActiveRocks) return;
TimeSpan elapsed = DateTime.Now - rockTimerStartTime;
if (IsGenerating)
{
GenerateRocks();
}
else
{
rockGeneratorTimer.Stop();
}
}
// 启动额外的石头生成定时器(增加生成量)
private void StartAdditionalGenerator()
{
if (additionalTimer != null)
{
additionalTimer.Stop();
additionalTimer.Tick -= AdditionalTimer_Tick;
}
additionalTimer = new DispatcherTimer();
additionalTimer.Interval = TimeSpan.FromMilliseconds(500); // 每500ms触发一次
additionalTimer.Tick += AdditionalTimer_Tick; // 绑定单独的事件方法
// 延迟1.5秒启动额外定时器(与主定时器同步延迟)
DispatcherTimer delayTimer = new DispatcherTimer();
delayTimer.Interval = TimeSpan.FromSeconds(0.5);
delayTimer.Tick += (s, e) =>
{
delayTimer.Stop(); // 关闭延迟定时器(只执行一次)
additionalTimerStartTime = DateTime.Now; // 记录额外定时器启动时间
additionalTimer.Start(); // 启动额外生成定时器
};
delayTimer.Start();
}
// 额外定时器的Tick事件单独提取
private void AdditionalTimer_Tick(object sender, EventArgs e)
{
if (currentRocks.Count >= MaxActiveRocks) return;
TimeSpan elapsed = DateTime.Now - additionalTimerStartTime;
if (IsGenerating)
{
for (int i = 0; i < 5; i++)
{
CreateFallingRockAnimation();
}
}
else
{
additionalTimer.Stop();
}
}
// 生成石头(由主定时器调用)
private void GenerateRocks()
{
int mainRocks = Math.Min(6, (int)(RocksPerSecond * rockGeneratorTimer.Interval.TotalSeconds) + 2);
for (int i = 0; i < mainRocks; i++)
{
CreateFallingRockAnimation();
}
}
// 创建下落的石头并启动动画
private void CreateFallingRockAnimation()
{
FrameworkElement rock = CreateRockShape(); // 创建石头形状
double rockWidth = rock.Width; // 石头宽度
double rockHeight = rock.Height; // 石头高度
// 设置石头起始位置(瓶子右侧外部)
double startX = 300 + random.Next(0, 100); // X:300-400之间
double startY = 80 - random.Next(0, 50); // Y:30-80之间
// 设置石头初始位置
Canvas.SetLeft(rock, startX);
Canvas.SetTop(rock, startY);
MainCanvas.Children.Add(rock); // 添加到画布
currentRocks.Add(rock); // 加入当前石头集合
// 启动下落动画
StartFallingAnimation(rock, startX, startY, rockWidth, rockHeight);
}
// 启动石头下落动画
private void StartFallingAnimation(FrameworkElement rock, double startX, double startY, double rockWidth, double rockHeight)
{
// 计算石头最终位置(瓶内)
double endY = RockSurfaceY - random.Next(0, 10); // Y:接近石头表面
double minEndX = 100; // X最小值(瓶子左边界)
double maxEndX = 300 - rockWidth; // X最大值(瓶子右边界)
double endX = random.Next((int)minEndX, (int)maxEndX + 1); // 随机X
// X方向移动动画(从右侧进入瓶内)
DoubleAnimation xAnimation = new DoubleAnimation
{
To = endX, // 目标X
Duration = TimeSpan.FromSeconds(0.8 + random.NextDouble() * 0.4), // 持续时间(0.8-1.2秒)
EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut } // 缓动函数(先快后慢)
};
// Y方向下落动画
DoubleAnimation yAnimation = new DoubleAnimation
{
To = endY, // 目标Y
Duration = TimeSpan.FromSeconds(1.0 + random.NextDouble() * 0.5), // 持续时间(0.6-0.9秒)
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn } // 缓动函数(先慢后快,模拟重力)
};
// 旋转动画(石头下落时旋转)
DoubleAnimation rotateAnimation = new DoubleAnimation
{
To = random.Next(-720, 720), // 旋转角度(-720到720度,随机方向)
Duration = TimeSpan.FromSeconds(1 + random.NextDouble() * 0.5) // 持续时间(1-1.5秒)
};
// 淡入动画(石头出现时逐渐显示)
DoubleAnimation fadeInAnimation = new DoubleAnimation
{
To = 1, // 目标透明度(完全显示)
Duration = TimeSpan.FromSeconds(0.3), // 持续时间0.3秒
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn } // 缓动函数
};
// 创建故事板(组合多个动画)
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(xAnimation);
storyboard.Children.Add(yAnimation);
storyboard.Children.Add(rotateAnimation);
storyboard.Children.Add(fadeInAnimation);
// 设置动画目标(绑定到石头控件)
Storyboard.SetTarget(xAnimation, rock);
Storyboard.SetTarget(yAnimation, rock);
Storyboard.SetTarget(rotateAnimation, rock);
Storyboard.SetTarget(fadeInAnimation, rock);
// 设置动画目标属性(路径)
Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(Canvas.Left)"));
Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(Canvas.Top)"));
Storyboard.SetTargetProperty(rotateAnimation, new PropertyPath("RenderTransform.Angle"));
Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath("Opacity"));
// 设置旋转中心(石头中心点)
rock.RenderTransformOrigin = new Point(0.5, 0.5);
rock.RenderTransform = new RotateTransform(); // 应用旋转变换
// 创建高度检查定时器(检测石头是否超过消失高度)
DispatcherTimer checkHeightTimer = new DispatcherTimer();
checkHeightTimer.Interval = TimeSpan.FromMilliseconds(50); // 每50ms检查一次
DateTime animationStartTime = DateTime.Now; // 动画开始时间
double animationDuration = yAnimation.Duration.TimeSpan.TotalSeconds; // 动画总时长
// 检查高度的定时器事件
checkHeightTimer.Tick += (s, e) =>
{
double elapsedTime = (DateTime.Now - animationStartTime).TotalSeconds; // 已过去时间
if (elapsedTime >= animationDuration)
{
checkHeightTimer.Stop(); // 动画结束,停止检查
return;
}
// 计算当前石头位置(根据动画进度)
double progress = elapsedTime / animationDuration;
double currentY = startY + (endY - startY) * progress;
// 如果超过消失高度,移除石头
if (currentY >= DisappearHeight)
{
checkHeightTimer.Stop();
RemoveRock(rock);
}
};
// 动画完成事件
storyboard.Completed += (s, e) =>
{
checkHeightTimer.Stop(); // 停止检查定时器
// 如果石头位置超过消失高度,移除石头
if (Canvas.GetTop(rock) >= DisappearHeight)
{
RemoveRock(rock);
}
};
checkHeightTimer.Start(); // 启动检查定时器
storyboard.Begin(); // 开始动画
}
// 移除石头(淡出动画后从画布移除)
private void RemoveRock(FrameworkElement rock)
{
if (MainCanvas.Children.Contains(rock))
{
// 创建淡出动画
DoubleAnimation fadeOutAnimation = new DoubleAnimation
{
To = 0, // 目标透明度(完全透明)
Duration = TimeSpan.FromSeconds(0.3), // 持续时间0.3秒
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut } // 缓动函数
};
// 淡出动画完成事件
fadeOutAnimation.Completed += (s, e) =>
{
// 从画布和集合中移除石头
if (MainCanvas.Children.Contains(rock))
{
MainCanvas.Children.Remove(rock);
}
currentRocks.Remove(rock);
};
// 启动淡出动画
rock.BeginAnimation(OpacityProperty, fadeOutAnimation);
}
}
// 公共方法:开始生成石头
public void StartGeneration()
{
IsGenerating = true;
}
// 公共方法:停止生成石头
public void StopGeneration()
{
IsGenerating = false;
}
// 公共方法:重置动画
public void ResetAnimation()
{
RemoveAllFallingRocks(); // 移除所有下落的石头
//DrawCylinderBottle(); // 重新绘制瓶子
//InitializeBottleRocks(); // 重新初始化瓶内石头
}
// 移除所有正在下落的石头
private void RemoveAllFallingRocks()
{
// 遍历当前石头集合,逐个移除
foreach (var rock in currentRocks.ToList())
{
RemoveRock(rock);
}
currentRocks.Clear(); // 清空当前集合
previousRocks.Clear(); // 清空之前集合
}
// 依赖属性变更回调:当每秒生成数量变化时
private static void OnRocksPerSecondChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is StoneCoke control && e.NewValue is int value)
{
if (value > 200)
{
control.RocksPerSecond = 200;
}
// 确保最小值为1(避免无效值)
if (value < 1)
{
control.RocksPerSecond = 1;
}
control.UpdateTimerInterval(); // 更新定时器间隔
}
}
// 依赖属性变更回调:当生成状态变化时
private static void OnIsGeneratingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is StoneCoke control)
{
if ((bool)e.NewValue)
{
// 开始生成:启动定时器
control.rockGeneratorTimer?.Start();
control.additionalTimer?.Start();
}
else
{
// 停止生成:停止定时器
control.rockGeneratorTimer?.Stop();
control.additionalTimer?.Stop();
}
}
}
// 更新生成定时器的间隔(根据每秒生成数量计算)
private void UpdateTimerInterval()
{
if (rockGeneratorTimer != null)
{
double interval = Math.Max(50, 1000.0 / RocksPerSecond); // 原20ms → 50ms
rockGeneratorTimer.Interval = TimeSpan.FromMilliseconds(interval);
}
}
// 清理资源(停止定时器并移除所有石头)
public void Cleanup()
{
rockGeneratorTimer?.Stop();
additionalTimer?.Stop();
RemoveAllFallingRocks();
}
}
}
我创建了项目名为WpfControlStone的用户控件项目名字,并创建了一个名字为StoneCoke的用户控件,使用canvas进行绘制红色石头进行下落的动画效果。
XML
<Window x:Class="FallingRocksFramework.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:FallingRocksFramework"
xmlns:coke="clr-namespace:wpfControlCoke;assembly=wpfControlCoke"
xmlns:stone="clr-namespace:WpfControlStone;assembly=WpfControlStone"(这句话需要引入)
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300"
AllowsTransparency="True"
Background="Transparent"
WindowStyle="None"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
>
<Grid>
<!--<coke:CokePushing />-->
<stone:StoneCoke />
</Grid>
</Window>
在创建一个wpf桌面应用程序项目,右键点击桌面程序项目选择添加里的引用

去选择你要引入的用户控件

去引用WpfControlStone用户控件,就可以进行运行查看了
20251009_101354