WinForms 可视化打印模板设计器

WinForms 打印模板设计器,支持拖拽设计、属性编辑、数据源绑定、条码/二维码、表格、图片、文本等元素,可直接用于票据、标签、报表打印。

一、项目结构

PrintTemplateDesigner/
├── PrintTemplateDesigner.csproj
├── Program.cs
├── MainForm.cs
├── MainForm.Designer.cs
├── Designer/
│   ├── DesignSurface.cs          ★ 设计画布
│   ├── ElementBase.cs           元素基类
│   ├── TextElement.cs           文本元素
│   ├── ImageElement.cs          图片元素
│   ├── LineElement.cs           线条元素
│   ├── RectangleElement.cs      矩形元素
│   ├── BarcodeElement.cs        条码元素
│   ├── TableElement.cs          表格元素
│   └── ElementFactory.cs        元素工厂
├── PropertyGrid/
│   ├── PropertyGridEx.cs       增强属性网格
│   ├── PropertyItem.cs          属性项
│   └── PropertyCategory.cs     属性分类
├── DataSource/
│   ├── DataSourceManager.cs    数据源管理
│   ├── DataTableSource.cs      表数据源
│   └── JsonDataSource.cs       JSON数据源
├── Printing/
│   ├── PrintEngine.cs          打印引擎
│   ├── PreviewForm.cs         打印预览
│   └── PrinterSettings.cs     打印机设置
├── Templates/
│   ├── Template.cs             模板模型
│   ├── TemplateSerializer.cs   模板序列化
│   └── TemplateManager.cs      模板管理
└── Utils/
    ├── DragDropManager.cs      拖拽管理
    ├── SelectionManager.cs     选择管理
    └── UndoRedoManager.cs      撤销重做

二、核心代码实现

1. 主程序入口 (Program.cs)

using System;
using System.Windows.Forms;

namespace PrintTemplateDesigner
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            // 设置高DPI支持
            Application.SetHighDpiMode(HighDpiMode.SystemAware);
            
            Application.Run(new MainForm());
        }
    }
}

2. 主窗体 (MainForm.cs)

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using PrintTemplateDesigner.Designer;
using PrintTemplateDesigner.PropertyGrid;
using PrintTemplateDesigner.Templates;
using PrintTemplateDesigner.Printing;
using PrintTemplateDesigner.DataSource;

namespace PrintTemplateDesigner
{
    public partial class MainForm : Form
    {
        private DesignSurface designSurface;
        private PropertyGridEx propertyGrid;
        private TemplateManager templateManager;
        private DataSourceManager dataSourceManager;
        private UndoRedoManager undoRedoManager;
        
        public MainForm()
        {
            InitializeComponent();
            InitializeComponents();
        }
        
        private void InitializeComponent()
        {
            this.Text = "打印模板设计器";
            this.Size = new Size(1400, 900);
            this.StartPosition = FormStartPosition.CenterScreen;
            this.WindowState = FormWindowState.Maximized;
            
            // 菜单栏
            MenuStrip menuStrip = new MenuStrip();
            
            // 文件菜单
            ToolStripMenuItem fileMenu = new ToolStripMenuItem("文件(&F)");
            fileMenu.DropDownItems.Add("新建模板", null, NewTemplate_Click);
            fileMenu.DropDownItems.Add("打开模板...", null, OpenTemplate_Click);
            fileMenu.DropDownItems.Add("保存模板", null, SaveTemplate_Click);
            fileMenu.DropDownItems.Add("另存为...", null, SaveAsTemplate_Click);
            fileMenu.DropDownItems.Add(new ToolStripSeparator());
            fileMenu.DropDownItems.Add("退出", null, (s, e) => Application.Exit());
            
            // 编辑菜单
            ToolStripMenuItem editMenu = new ToolStripMenuItem("编辑(&E)");
            editMenu.DropDownItems.Add("撤销", null, Undo_Click);
            editMenu.DropDownItems.Add("重做", null, Redo_Click);
            editMenu.DropDownItems.Add(new ToolStripSeparator());
            editMenu.DropDownItems.Add("剪切", null, Cut_Click);
            editMenu.DropDownItems.Add("复制", null, Copy_Click);
            editMenu.DropDownItems.Add("粘贴", null, Paste_Click);
            editMenu.DropDownItems.Add(new ToolStripSeparator());
            editMenu.DropDownItems.Add("删除", null, Delete_Click);
            
            // 视图菜单
            ToolStripMenuItem viewMenu = new ToolStripMenuItem("视图(&V)");
            viewMenu.DropDownItems.Add("显示网格", null, ToggleGrid);
            viewMenu.DropDownItems.Add("对齐到网格", null, ToggleSnapToGrid);
            viewMenu.DropDownItems.Add("显示标尺", null, ToggleRuler);
            
            // 模板菜单
            ToolStripMenuItem templateMenu = new ToolStripMenuItem("模板(&T)");
            templateMenu.DropDownItems.Add("页面设置...", null, PageSetup_Click);
            templateMenu.DropDownItems.Add("数据源设置...", null, DataSource_Click);
            templateMenu.DropDownItems.Add(new ToolStripSeparator());
            templateMenu.DropDownItems.Add("打印预览", null, PrintPreview_Click);
            templateMenu.DropDownItems.Add("打印...", null, Print_Click);
            
            menuStrip.Items.AddRange(new ToolStripItem[] { fileMenu, editMenu, viewMenu, templateMenu });
            
            // 工具栏
            ToolStrip toolStrip = new ToolStrip();
            
            // 文件操作
            ToolStripButton btnNew = new ToolStripButton("新建");
            btnNew.Click += NewTemplate_Click;
            
            ToolStripButton btnOpen = new ToolStripButton("打开");
            btnOpen.Click += OpenTemplate_Click;
            
            ToolStripButton btnSave = new ToolStripButton("保存");
            btnSave.Click += SaveTemplate_Click;
            
            toolStrip.Items.AddRange(new ToolStripItem[] { btnNew, btnOpen, btnSave });
            
            // 布局
            SplitContainer mainSplit = new SplitContainer
            {
                Dock = DockStyle.Fill,
                Orientation = Orientation.Vertical,
                SplitterDistance = 250
            };
            
            SplitContainer rightSplit = new SplitContainer
            {
                Dock = DockStyle.Fill,
                Orientation = Orientation.Horizontal,
                SplitterDistance = 600
            };
            
            // 左侧工具箱
            Panel toolboxPanel = CreateToolboxPanel();
            mainSplit.Panel1.Controls.Add(toolboxPanel);
            
            // 中间设计区域
            designSurface = new DesignSurface
            {
                Dock = DockStyle.Fill,
                BackColor = Color.White,
                GridVisible = true,
                SnapToGrid = true,
                RulerVisible = true
            };
            designSurface.ElementSelected += DesignSurface_ElementSelected;
            designSurface.ElementChanged += DesignSurface_ElementChanged;
            rightSplit.Panel1.Controls.Add(designSurface);
            
            // 右侧属性面板
            propertyGrid = new PropertyGridEx
            {
                Dock = DockStyle.Fill
            };
            rightSplit.Panel2.Controls.Add(propertyGrid);
            
            mainSplit.Panel2.Controls.Add(rightSplit);
            
            this.Controls.Add(menuStrip);
            this.Controls.Add(toolStrip);
            this.Controls.Add(mainSplit);
            
            // 初始化管理器
            templateManager = new TemplateManager();
            dataSourceManager = new DataSourceManager();
            undoRedoManager = new UndoRedoManager();
            
            // 创建新模板
            NewTemplate();
        }
        
        private Panel CreateToolboxPanel()
        {
            Panel panel = new Panel
            {
                Dock = DockStyle.Fill,
                BackColor = SystemColors.Control
            };
            
            Label lblTitle = new Label
            {
                Text = "工具箱",
                Dock = DockStyle.Top,
                Height = 30,
                TextAlign = ContentAlignment.MiddleCenter,
                Font = new Font("微软雅黑", 10, FontStyle.Bold)
            };
            
            FlowLayoutPanel flowPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.TopDown,
                WrapContents = false,
                AutoScroll = true,
                Padding = new Padding(5)
            };
            
            // 添加工具项
            string[] tools = {
                "文本", "图片", "线条", "矩形", "圆角矩形",
                "条码", "二维码", "表格", "页码", "日期时间"
            };
            
            foreach (string tool in tools)
            {
                Button btn = new Button
                {
                    Text = tool,
                    Size = new Size(100, 35),
                    Margin = new Padding(0, 0, 0, 5),
                    Tag = tool
                };
                btn.MouseDown += Tool_MouseDown;
                flowPanel.Controls.Add(btn);
            }
            
            panel.Controls.Add(flowPanel);
            panel.Controls.Add(lblTitle);
            
            return panel;
        }
        
        #region 事件处理
        
        private void NewTemplate_Click(object sender, EventArgs e)
        {
            designSurface.Clear();
            designSurface.PageWidth = 210;  // A4宽度 mm
            designSurface.PageHeight = 297; // A4高度 mm
            designSurface.MarginLeft = 10;
            designSurface.MarginTop = 10;
            designSurface.MarginRight = 10;
            designSurface.MarginBottom = 10;
            
            undoRedoManager.Clear();
            UpdateStatus("新建模板已创建");
        }
        
        private void OpenTemplate_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog dialog = new OpenFileDialog())
            {
                dialog.Filter = "模板文件|*.ptd|所有文件|*.*";
                dialog.Title = "打开模板";
                
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    Template template = templateManager.Load(dialog.FileName);
                    designSurface.LoadTemplate(template);
                    UpdateStatus($"已加载模板: {Path.GetFileName(dialog.FileName)}");
                }
            }
        }
        
        private void SaveTemplate_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(templateManager.CurrentFilePath))
            {
                SaveAsTemplate_Click(sender, e);
                return;
            }
            
            Template template = designSurface.GetTemplate();
            templateManager.Save(template, templateManager.CurrentFilePath);
            UpdateStatus("模板已保存");
        }
        
        private void SaveAsTemplate_Click(object sender, EventArgs e)
        {
            using (SaveFileDialog dialog = new SaveFileDialog())
            {
                dialog.Filter = "模板文件|*.ptd|所有文件|*.*";
                dialog.Title = "保存模板";
                dialog.FileName = "未命名模板.ptd";
                
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    Template template = designSurface.GetTemplate();
                    templateManager.Save(template, dialog.FileName);
                    templateManager.CurrentFilePath = dialog.FileName;
                    UpdateStatus($"模板已保存到: {Path.GetFileName(dialog.FileName)}");
                }
            }
        }
        
        private void Undo_Click(object sender, EventArgs e)
        {
            undoRedoManager.Undo();
            UpdateStatus("撤销");
        }
        
        private void Redo_Click(object sender, EventArgs e)
        {
            undoRedoManager.Redo();
            UpdateStatus("重做");
        }
        
        private void Cut_Click(object sender, EventArgs e)
        {
            designSurface.CutSelectedElements();
            UpdateStatus("剪切");
        }
        
        private void Copy_Click(object sender, EventArgs e)
        {
            designSurface.CopySelectedElements();
            UpdateStatus("复制");
        }
        
        private void Paste_Click(object sender, EventArgs e)
        {
            designSurface.PasteElements();
            UpdateStatus("粘贴");
        }
        
        private void Delete_Click(object sender, EventArgs e)
        {
            designSurface.DeleteSelectedElements();
            UpdateStatus("删除");
        }
        
        private void ToggleGrid(object sender, EventArgs e)
        {
            designSurface.GridVisible = !designSurface.GridVisible;
            UpdateStatus($"网格显示: {(designSurface.GridVisible ? "开" : "关")}");
        }
        
        private void ToggleSnapToGrid(object sender, EventArgs e)
        {
            designSurface.SnapToGrid = !designSurface.SnapToGrid;
            UpdateStatus($"对齐网格: {(designSurface.SnapToGrid ? "开" : "关")}");
        }
        
        private void ToggleRuler(object sender, EventArgs e)
        {
            designSurface.RulerVisible = !designSurface.RulerVisible;
            UpdateStatus($"标尺显示: {(designSurface.RulerVisible ? "开" : "关")}");
        }
        
        private void PageSetup_Click(object sender, EventArgs e)
        {
            using (PageSetupForm form = new PageSetupForm(designSurface))
            {
                if (form.ShowDialog() == DialogResult.OK)
                {
                    designSurface.Invalidate();
                    UpdateStatus("页面设置已更新");
                }
            }
        }
        
        private void DataSource_Click(object sender, EventArgs e)
        {
            using (DataSourceForm form = new DataSourceForm(dataSourceManager))
            {
                if (form.ShowDialog() == DialogResult.OK)
                {
                    UpdateStatus("数据源已更新");
                }
            }
        }
        
        private void PrintPreview_Click(object sender, EventArgs e)
        {
            Template template = designSurface.GetTemplate();
            using (PreviewForm preview = new PreviewForm(template, dataSourceManager))
            {
                preview.ShowDialog();
            }
        }
        
        private void Print_Click(object sender, EventArgs e)
        {
            Template template = designSurface.GetTemplate();
            PrintEngine printer = new PrintEngine(template, dataSourceManager);
            printer.Print();
            UpdateStatus("打印完成");
        }
        
        private void Tool_MouseDown(object sender, MouseEventArgs e)
        {
            Button btn = sender as Button;
            if (btn == null) return;
            
            string toolType = btn.Tag.ToString();
            designSurface.StartDragCreate(toolType);
        }
        
        private void DesignSurface_ElementSelected(object sender, ElementBase element)
        {
            propertyGrid.SelectedObject = element;
        }
        
        private void DesignSurface_ElementChanged(object sender, EventArgs e)
        {
            undoRedoManager.RecordState(designSurface.GetTemplate());
        }
        
        private void UpdateStatus(string message)
        {
            // 更新状态栏
            statusLabel.Text = message;
        }
        
        #endregion
        
        // 控件声明
        private StatusStrip statusStrip;
        private ToolStripStatusLabel statusLabel;
    }
}

3. 设计画布 (DesignSurface.cs)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using PrintTemplateDesigner.Designer;
using PrintTemplateDesigner.Utils;

namespace PrintTemplateDesigner
{
    public class DesignSurface : UserControl
    {
        public event EventHandler<ElementBase> ElementSelected;
        public event EventHandler ElementChanged;
        
        // 页面属性
        public float PageWidth { get; set; } = 210;   // mm
        public float PageHeight { get; set; } = 297;  // mm
        public float MarginLeft { get; set; } = 10;
        public float MarginTop { get; set; } = 10;
        public float MarginRight { get; set; } = 10;
        public float MarginBottom { get; set; } = 10;
        
        // 显示属性
        public bool GridVisible { get; set; } = true;
        public bool SnapToGrid { get; set; } = true;
        public bool RulerVisible { get; set; } = true;
        public int GridSize { get; set; } = 5; // mm
        
        private List<ElementBase> elements = new List<ElementBase>();
        private ElementBase selectedElement;
        private SelectionManager selectionManager;
        private DragDropManager dragDropManager;
        private PointF mouseDownLocation;
        private bool isDragging = false;
        private bool isResizing = false;
        private ResizeHandle resizeHandle = ResizeHandle.None;
        
        // 设计模式
        private string createToolType = null;
        private bool isCreating = false;
        
        public DesignSurface()
        {
            InitializeComponent();
            selectionManager = new SelectionManager(this);
            dragDropManager = new DragDropManager(this);
            
            this.DoubleBuffered = true;
            this.BackColor = Color.White;
            this.AllowDrop = true;
        }
        
        private void InitializeComponent()
        {
            this.MouseDown += DesignSurface_MouseDown;
            this.MouseMove += DesignSurface_MouseMove;
            this.MouseUp += DesignSurface_MouseUp;
            this.Paint += DesignSurface_Paint;
            this.KeyDown += DesignSurface_KeyDown;
        }
        
        public void Clear()
        {
            elements.Clear();
            selectedElement = null;
            Invalidate();
        }
        
        public void StartDragCreate(string toolType)
        {
            createToolType = toolType;
            isCreating = true;
            Cursor = Cursors.Cross;
        }
        
        public void LoadTemplate(Template template)
        {
            Clear();
            
            PageWidth = template.PageWidth;
            PageHeight = template.PageHeight;
            MarginLeft = template.MarginLeft;
            MarginTop = template.MarginTop;
            MarginRight = template.MarginRight;
            MarginBottom = template.MarginBottom;
            
            foreach (var elemData in template.Elements)
            {
                ElementBase element = ElementFactory.CreateElement(elemData.Type);
                element.LoadFromData(elemData);
                elements.Add(element);
            }
            
            Invalidate();
        }
        
        public Template GetTemplate()
        {
            Template template = new Template
            {
                PageWidth = PageWidth,
                PageHeight = PageHeight,
                MarginLeft = MarginLeft,
                MarginTop = MarginTop,
                MarginRight = MarginRight,
                MarginBottom = MarginBottom
            };
            
            foreach (var element in elements)
            {
                template.Elements.Add(element.GetData());
            }
            
            return template;
        }
        
        #region 鼠标事件
        
        private void DesignSurface_MouseDown(object sender, MouseEventArgs e)
        {
            PointF location = PixelToMm(e.Location);
            
            if (isCreating)
            {
                // 开始创建新元素
                mouseDownLocation = location;
                isCreating = true;
            }
            else
            {
                // 选择元素
                selectedElement = HitTest(location);
                if (selectedElement != null)
                {
                    selectionManager.Select(selectedElement);
                    
                    // 检查是否在调整大小的手柄上
                    resizeHandle = selectionManager.HitTestResizeHandle(e.Location);
                    if (resizeHandle != ResizeHandle.None)
                    {
                        isResizing = true;
                    }
                    else
                    {
                        isDragging = true;
                        mouseDownLocation = location;
                    }
                }
                else
                {
                    selectionManager.ClearSelection();
                }
            }
            
            Invalidate();
            ElementSelected?.Invoke(this, selectedElement);
        }
        
        private void DesignSurface_MouseMove(object sender, MouseEventArgs e)
        {
            PointF location = PixelToMm(e.Location);
            
            if (isCreating && createToolType != null)
            {
                // 绘制创建预览
                Invalidate();
            }
            else if (isDragging && selectedElement != null)
            {
                // 拖动元素
                float deltaX = location.X - mouseDownLocation.X;
                float deltaY = location.Y - mouseDownLocation.Y;
                
                selectedElement.Move(deltaX, deltaY);
                mouseDownLocation = location;
                
                Invalidate();
                ElementChanged?.Invoke(this, EventArgs.Empty);
            }
            else if (isResizing && selectedElement != null)
            {
                // 调整大小
                selectedElement.Resize(resizeHandle, location);
                Invalidate();
                ElementChanged?.Invoke(this, EventArgs.Empty);
            }
        }
        
        private void DesignSurface_MouseUp(object sender, MouseEventArgs e)
        {
            if (isCreating && createToolType != null)
            {
                PointF location = PixelToMm(e.Location);
                CreateElement(createToolType, mouseDownLocation, location);
                isCreating = false;
                createToolType = null;
                Cursor = Cursors.Default;
            }
            
            isDragging = false;
            isResizing = false;
            resizeHandle = ResizeHandle.None;
        }
        
        private void DesignSurface_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete && selectedElement != null)
            {
                DeleteSelectedElements();
            }
            else if (e.Control && e.KeyCode == Keys.C)
            {
                CopySelectedElements();
            }
            else if (e.Control && e.KeyCode == Keys.V)
            {
                PasteElements();
            }
        }
        
        #endregion
        
        #region 元素操作
        
        private void CreateElement(string type, PointF start, PointF end)
        {
            ElementBase element = ElementFactory.CreateElement(type);
            if (element == null) return;
            
            float x = Math.Min(start.X, end.X);
            float y = Math.Min(start.Y, end.Y);
            float width = Math.Abs(end.X - start.X);
            float height = Math.Abs(end.Y - start.Y);
            
            // 最小尺寸
            if (width < 10) width = 50;
            if (height < 10) height = 20;
            
            element.SetBounds(x, y, width, height);
            element.Name = GenerateElementName(type);
            
            elements.Add(element);
            selectedElement = element;
            
            Invalidate();
            ElementChanged?.Invoke(this, EventArgs.Empty);
        }
        
        private string GenerateElementName(string type)
        {
            int count = 0;
            foreach (var elem in elements)
            {
                if (elem.Type == type) count++;
            }
            return $"{type}_{count + 1}";
        }
        
        private ElementBase HitTest(PointF location)
        {
            for (int i = elements.Count - 1; i >= 0; i--)
            {
                if (elements[i].HitTest(location))
                {
                    return elements[i];
                }
            }
            return null;
        }
        
        public void DeleteSelectedElements()
        {
            if (selectedElement != null)
            {
                elements.Remove(selectedElement);
                selectedElement = null;
                Invalidate();
                ElementChanged?.Invoke(this, EventArgs.Empty);
            }
        }
        
        public void CutSelectedElements()
        {
            CopySelectedElements();
            DeleteSelectedElements();
        }
        
        public void CopySelectedElements()
        {
            if (selectedElement != null)
            {
                Clipboard.SetData("PrintElement", selectedElement.Clone());
            }
        }
        
        public void PasteElements()
        {
            if (Clipboard.ContainsData("PrintElement"))
            {
                ElementBase element = Clipboard.GetData("PrintElement") as ElementBase;
                if (element != null)
                {
                    element = element.Clone();
                    element.Move(10, 10); // 偏移一点避免重叠
                    elements.Add(element);
                    selectedElement = element;
                    Invalidate();
                    ElementChanged?.Invoke(this, EventArgs.Empty);
                }
            }
        }
        
        #endregion
        
        #region 绘制
        
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            
            // 绘制背景
            g.Clear(BackColor);
            
            // 绘制网格
            if (GridVisible)
            {
                DrawGrid(g);
            }
            
            // 绘制页面边界
            DrawPageBounds(g);
            
            // 绘制元素
            foreach (var element in elements)
            {
                element.Draw(g, selectedElement == element);
            }
            
            // 绘制创建预览
            if (isCreating && createToolType != null)
            {
                DrawCreatePreview(g);
            }
            
            // 绘制选择框和调整手柄
            if (selectedElement != null)
            {
                selectionManager.DrawSelection(g, selectedElement);
            }
        }
        
        private void DrawGrid(Graphics g)
        {
            float gridSizePx = MmToPixel(GridSize);
            Pen gridPen = new Pen(Color.LightGray, 1);
            gridPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            
            for (float x = 0; x < Width; x += gridSizePx)
            {
                g.DrawLine(gridPen, x, 0, x, Height);
            }
            
            for (float y = 0; y < Height; y += gridSizePx)
            {
                g.DrawLine(gridPen, 0, y, Width, y);
            }
        }
        
        private void DrawPageBounds(Graphics g)
        {
            RectangleF pageRect = GetPageRect();
            Pen borderPen = new Pen(Color.DarkGray, 2);
            g.DrawRectangle(borderPen, pageRect.X, pageRect.Y, pageRect.Width, pageRect.Height);
            
            // 绘制边距
            RectangleF marginRect = new RectangleF(
                pageRect.X + MmToPixel(MarginLeft),
                pageRect.Y + MmToPixel(MarginTop),
                pageRect.Width - MmToPixel(MarginLeft + MarginRight),
                pageRect.Height - MmToPixel(MarginTop + MarginBottom)
            );
            
            Pen marginPen = new Pen(Color.LightBlue, 1);
            marginPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            g.DrawRectangle(marginPen, marginRect.X, marginRect.Y, marginRect.Width, marginRect.Height);
        }
        
        private void DrawCreatePreview(Graphics g)
        {
            // 绘制创建预览
        }
        
        private RectangleF GetPageRect()
        {
            float width = MmToPixel(PageWidth);
            float height = MmToPixel(PageHeight);
            float x = (Width - width) / 2;
            float y = (Height - height) / 2;
            return new RectangleF(x, y, width, height);
        }
        
        #endregion
        
        #region 坐标转换
        
        private PointF PixelToMm(PointF pixel)
        {
            float dpiX = 96; // 假设96 DPI
            float dpiY = 96;
            float mmPerInch = 25.4f;
            
            float x = pixel.X / dpiX * mmPerInch;
            float y = pixel.Y / dpiY * mmPerInch;
            
            // 减去页面偏移
            RectangleF pageRect = GetPageRect();
            x -= pageRect.X / dpiX * mmPerInch;
            y -= pageRect.Y / dpiY * mmPerInch;
            
            return new PointF(x, y);
        }
        
        private float MmToPixel(float mm)
        {
            float dpi = 96;
            float mmPerInch = 25.4f;
            return mm / mmPerInch * dpi;
        }
        
        #endregion
    }
    
    public enum ResizeHandle
    {
        None,
        TopLeft,
        Top,
        TopRight,
        Right,
        BottomRight,
        Bottom,
        BottomLeft,
        Left
    }
}

4. 元素基类 (ElementBase.cs)

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using PrintTemplateDesigner.Templates;

namespace PrintTemplateDesigner.Designer
{
    public abstract class ElementBase : ICloneable
    {
        public string Name { get; set; }
        public string Type { get; protected set; }
        public float X { get; set; }
        public float Y { get; set; }
        public float Width { get; set; }
        public float Height { get; set; }
        public bool Visible { get; set; } = true;
        public bool Locked { get; set; } = false;
        
        // 样式属性
        public Color ForeColor { get; set; } = Color.Black;
        public Color BackColor { get; set; } = Color.Transparent;
        public Font Font { get; set; } = new Font("微软雅黑", 10);
        public StringFormat TextAlign { get; set; } = new StringFormat();
        public float LineWidth { get; set; } = 1;
        public DashStyle LineStyle { get; set; } = DashStyle.Solid;
        
        // 数据源绑定
        public string DataField { get; set; }
        public string Format { get; set; }
        
        protected ElementBase()
        {
            TextAlign.Alignment = StringAlignment.Near;
            TextAlign.LineAlignment = StringAlignment.Center;
        }
        
        public abstract void Draw(Graphics g, bool isSelected);
        public abstract ElementData GetData();
        public abstract void LoadFromData(ElementData data);
        
        public virtual bool HitTest(PointF point)
        {
            return new RectangleF(X, Y, Width, Height).Contains(point);
        }
        
        public virtual void Move(float deltaX, float deltaY)
        {
            if (Locked) return;
            
            X += deltaX;
            Y += deltaY;
        }
        
        public virtual void Resize(ResizeHandle handle, PointF newPosition)
        {
            if (Locked) return;
            
            switch (handle)
            {
                case ResizeHandle.TopLeft:
                    Width += X - newPosition.X;
                    Height += Y - newPosition.Y;
                    X = newPosition.X;
                    Y = newPosition.Y;
                    break;
                case ResizeHandle.TopRight:
                    Width = newPosition.X - X;
                    Height += Y - newPosition.Y;
                    Y = newPosition.Y;
                    break;
                case ResizeHandle.BottomLeft:
                    Width += X - newPosition.X;
                    Height = newPosition.Y - Y;
                    X = newPosition.X;
                    break;
                case ResizeHandle.BottomRight:
                    Width = newPosition.X - X;
                    Height = newPosition.Y - Y;
                    break;
                case ResizeHandle.Top:
                    Height += Y - newPosition.Y;
                    Y = newPosition.Y;
                    break;
                case ResizeHandle.Bottom:
                    Height = newPosition.Y - Y;
                    break;
                case ResizeHandle.Left:
                    Width += X - newPosition.X;
                    X = newPosition.X;
                    break;
                case ResizeHandle.Right:
                    Width = newPosition.X - X;
                    break;
            }
            
            // 确保最小尺寸
            if (Width < 5) Width = 5;
            if (Height < 5) Height = 5;
        }
        
        public void SetBounds(float x, float y, float width, float height)
        {
            X = x;
            Y = y;
            Width = width;
            Height = height;
        }
        
        public object Clone()
        {
            ElementBase clone = (ElementBase)this.MemberwiseClone();
            clone.Font = (Font)this.Font.Clone();
            clone.TextAlign = (StringFormat)this.TextAlign.Clone();
            return clone;
        }
        
        protected void DrawSelectionHandles(Graphics g, RectangleF bounds)
        {
            float handleSize = 6;
            Pen handlePen = new Pen(Color.Blue, 1);
            Brush handleBrush = Brushes.White;
            
            RectangleF[] handles = {
                new RectangleF(bounds.X - handleSize/2, bounds.Y - handleSize/2, handleSize, handleSize), // TopLeft
                new RectangleF(bounds.X + bounds.Width/2 - handleSize/2, bounds.Y - handleSize/2, handleSize, handleSize), // Top
                new RectangleF(bounds.X + bounds.Width - handleSize/2, bounds.Y - handleSize/2, handleSize, handleSize), // TopRight
                new RectangleF(bounds.X + bounds.Width - handleSize/2, bounds.Y + bounds.Height/2 - handleSize/2, handleSize, handleSize), // Right
                new RectangleF(bounds.X + bounds.Width - handleSize/2, bounds.Y + bounds.Height - handleSize/2, handleSize, handleSize), // BottomRight
                new RectangleF(bounds.X + bounds.Width/2 - handleSize/2, bounds.Y + bounds.Height - handleSize/2, handleSize, handleSize), // Bottom
                new RectangleF(bounds.X - handleSize/2, bounds.Y + bounds.Height - handleSize/2, handleSize, handleSize), // BottomLeft
                new RectangleF(bounds.X - handleSize/2, bounds.Y + bounds.Height/2 - handleSize/2, handleSize, handleSize) // Left
            };
            
            foreach (var handle in handles)
            {
                g.FillRectangle(handleBrush, handle);
                g.DrawRectangle(handlePen, handle.X, handle.Y, handle.Width, handle.Height);
            }
        }
    }
}

5. 文本元素 (TextElement.cs)

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using PrintTemplateDesigner.Templates;

namespace PrintTemplateDesigner.Designer
{
    public class TextElement : ElementBase
    {
        public string Text { get; set; } = "文本";
        public bool AutoSize { get; set; } = true;
        public bool WordWrap { get; set; } = true;
        
        public TextElement()
        {
            Type = "Text";
            Name = "文本";
            Width = 100;
            Height = 30;
        }
        
        public override void Draw(Graphics g, bool isSelected)
        {
            if (!Visible) return;
            
            RectangleF bounds = new RectangleF(X, Y, Width, Height);
            
            // 绘制背景
            if (BackColor != Color.Transparent)
            {
                using (Brush backBrush = new SolidBrush(BackColor))
                {
                    g.FillRectangle(backBrush, bounds);
                }
            }
            
            // 绘制文本
            string displayText = Text;
            if (!string.IsNullOrEmpty(DataField))
            {
                displayText = $"[{DataField}]";
            }
            
            using (Brush textBrush = new SolidBrush(ForeColor))
            {
                if (WordWrap)
                {
                    g.DrawString(displayText, Font, textBrush, bounds, TextAlign);
                }
                else
                {
                    // 单行,不换行
                    StringFormat sf = (StringFormat)TextAlign.Clone();
                    sf.FormatFlags |= StringFormatFlags.NoWrap;
                    g.DrawString(displayText, Font, textBrush, bounds, sf);
                }
            }
            
            // 绘制边框(选中时)
            if (isSelected)
            {
                using (Pen borderPen = new Pen(Color.Blue, 1))
                {
                    borderPen.DashStyle = DashStyle.Dash;
                    g.DrawRectangle(borderPen, bounds.X, bounds.Y, bounds.Width, bounds.Height);
                }
                
                // 绘制调整手柄
                DrawSelectionHandles(g, bounds);
            }
        }
        
        public override ElementData GetData()
        {
            return new ElementData
            {
                Type = Type,
                Name = Name,
                X = X,
                Y = Y,
                Width = Width,
                Height = Height,
                Properties = new System.Collections.Generic.Dictionary<string, object>
                {
                    { "Text", Text },
                    { "ForeColor", ForeColor.ToArgb() },
                    { "BackColor", BackColor.ToArgb() },
                    { "FontName", Font.Name },
                    { "FontSize", Font.Size },
                    { "FontStyle", (int)Font.Style },
                    { "TextAlign", (int)TextAlign.Alignment },
                    { "LineWidth", LineWidth },
                    { "DataField", DataField },
                    { "Format", Format },
                    { "AutoSize", AutoSize },
                    { "WordWrap", WordWrap }
                }
            };
        }
        
        public override void LoadFromData(ElementData data)
        {
            Name = data.Name;
            X = data.X;
            Y = data.Y;
            Width = data.Width;
            Height = data.Height;
            
            if (data.Properties.ContainsKey("Text")) Text = data.Properties["Text"].ToString();
            if (data.Properties.ContainsKey("ForeColor")) ForeColor = Color.FromArgb((int)data.Properties["ForeColor"]);
            if (data.Properties.ContainsKey("BackColor")) BackColor = Color.FromArgb((int)data.Properties["BackColor"]);
            if (data.Properties.ContainsKey("FontName")) 
            {
                string fontName = data.Properties["FontName"].ToString();
                float fontSize = 10;
                FontStyle fontStyle = FontStyle.Regular;
                
                if (data.Properties.ContainsKey("FontSize")) fontSize = Convert.ToSingle(data.Properties["FontSize"]);
                if (data.Properties.ContainsKey("FontStyle")) fontStyle = (FontStyle)Convert.ToInt32(data.Properties["FontStyle"]);
                
                Font = new Font(fontName, fontSize, fontStyle);
            }
            if (data.Properties.ContainsKey("DataField")) DataField = data.Properties["DataField"].ToString();
            if (data.Properties.ContainsKey("Format")) Format = data.Properties["Format"].ToString();
            if (data.Properties.ContainsKey("AutoSize")) AutoSize = Convert.ToBoolean(data.Properties["AutoSize"]);
            if (data.Properties.ContainsKey("WordWrap")) WordWrap = Convert.ToBoolean(data.Properties["WordWrap"]);
        }
    }
}

6. 条码元素 (BarcodeElement.cs)

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using PrintTemplateDesigner.Templates;

namespace PrintTemplateDesigner.Designer
{
    public class BarcodeElement : ElementBase
    {
        public string BarcodeType { get; set; } = "Code128";
        public string BarcodeData { get; set; } = "123456789012";
        public bool ShowText { get; set; } = true;
        public int BarHeight { get; set; } = 50;
        
        public BarcodeElement()
        {
            Type = "Barcode";
            Name = "条码";
            Width = 200;
            Height = 80;
        }
        
        public override void Draw(Graphics g, bool isSelected)
        {
            if (!Visible) return;
            
            RectangleF bounds = new RectangleF(X, Y, Width, Height);
            
            // 绘制背景
            if (BackColor != Color.Transparent)
            {
                using (Brush backBrush = new SolidBrush(BackColor))
                {
                    g.FillRectangle(backBrush, bounds);
                }
            }
            
            // 绘制条码
            string data = BarcodeData;
            if (!string.IsNullOrEmpty(DataField))
            {
                data = $"[{DataField}]";
            }
            
            DrawBarcode(g, data, bounds);
            
            // 绘制边框(选中时)
            if (isSelected)
            {
                using (Pen borderPen = new Pen(Color.Blue, 1))
                {
                    borderPen.DashStyle = DashStyle.Dash;
                    g.DrawRectangle(borderPen, bounds.X, bounds.Y, bounds.Width, bounds.Height);
                }
                
                DrawSelectionHandles(g, bounds);
            }
        }
        
        private void DrawBarcode(Graphics g, string data, RectangleF bounds)
        {
            // 简化的条码绘制(实际应使用专业的条码库)
            float barWidth = bounds.Width / (data.Length * 3);
            float barHeight = bounds.Height - (ShowText ? 20 : 0);
            
            Random rnd = new Random(data.GetHashCode());
            
            for (int i = 0; i < data.Length; i++)
            {
                int pattern = rnd.Next(0, 7); // 模拟条码图案
                int bars = pattern % 3 + 1;
                
                for (int j = 0; j < bars; j++)
                {
                    float x = bounds.X + i * barWidth * 3 + j * barWidth;
                    float y = bounds.Y;
                    
                    using (Brush barBrush = new SolidBrush(ForeColor))
                    {
                        g.FillRectangle(barBrush, x, y, barWidth * 0.8f, barHeight);
                    }
                }
            }
            
            // 绘制文本
            if (ShowText)
            {
                using (Brush textBrush = new SolidBrush(ForeColor))
                {
                    StringFormat sf = new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center
                    };
                    
                    RectangleF textRect = new RectangleF(bounds.X, bounds.Y + barHeight, bounds.Width, 20);
                    g.DrawString(data, new Font("Arial", 8), textBrush, textRect, sf);
                }
            }
        }
        
        public override ElementData GetData()
        {
            return new ElementData
            {
                Type = Type,
                Name = Name,
                X = X,
                Y = Y,
                Width = Width,
                Height = Height,
                Properties = new System.Collections.Generic.Dictionary<string, object>
                {
                    { "BarcodeType", BarcodeType },
                    { "BarcodeData", BarcodeData },
                    { "ShowText", ShowText },
                    { "BarHeight", BarHeight },
                    { "ForeColor", ForeColor.ToArgb() },
                    { "BackColor", BackColor.ToArgb() },
                    { "DataField", DataField },
                    { "Format", Format }
                }
            };
        }
        
        public override void LoadFromData(ElementData data)
        {
            Name = data.Name;
            X = data.X;
            Y = data.Y;
            Width = data.Width;
            Height = data.Height;
            
            if (data.Properties.ContainsKey("BarcodeType")) BarcodeType = data.Properties["BarcodeType"].ToString();
            if (data.Properties.ContainsKey("BarcodeData")) BarcodeData = data.Properties["BarcodeData"].ToString();
            if (data.Properties.ContainsKey("ShowText")) ShowText = Convert.ToBoolean(data.Properties["ShowText"]);
            if (data.Properties.ContainsKey("BarHeight")) BarHeight = Convert.ToInt32(data.Properties["BarHeight"]);
            if (data.Properties.ContainsKey("ForeColor")) ForeColor = Color.FromArgb((int)data.Properties["ForeColor"]);
            if (data.Properties.ContainsKey("BackColor")) BackColor = Color.FromArgb((int)data.Properties["BackColor"]);
            if (data.Properties.ContainsKey("DataField")) DataField = data.Properties["DataField"].ToString();
            if (data.Properties.ContainsKey("Format")) Format = data.Properties["Format"].ToString();
        }
    }
}

7. 模板模型 (Template.cs)

using System;
using System.Collections.Generic;

namespace PrintTemplateDesigner.Templates
{
    public class Template
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public DateTime CreatedDate { get; set; }
        public DateTime ModifiedDate { get; set; }
        
        // 页面设置
        public float PageWidth { get; set; } = 210;   // mm
        public float PageHeight { get; set; } = 297;  // mm
        public float MarginLeft { get; set; } = 10;
        public float MarginTop { get; set; } = 10;
        public float MarginRight { get; set; } = 10;
        public float MarginBottom { get; set; } = 10;
        
        // 打印设置
        public string PrinterName { get; set; }
        public int Copies { get; set; } = 1;
        public bool Landscape { get; set; } = false;
        public int PaperSource { get; set; } = 0;
        
        // 数据源
        public string DataSourceType { get; set; } = "None";
        public string ConnectionString { get; set; }
        public string Query { get; set; }
        
        // 元素集合
        public List<ElementData> Elements { get; set; } = new List<ElementData>();
        
        public Template()
        {
            CreatedDate = DateTime.Now;
            ModifiedDate = DateTime.Now;
        }
    }
    
    public class ElementData
    {
        public string Type { get; set; }
        public string Name { get; set; }
        public float X { get; set; }
        public float Y { get; set; }
        public float Width { get; set; }
        public float Height { get; set; }
        public Dictionary<string, object> Properties { get; set; } = new Dictionary<string, object>();
    }
}

8. 打印引擎 (PrintEngine.cs)

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Collections.Generic;
using PrintTemplateDesigner.Templates;
using PrintTemplateDesigner.DataSource;
using PrintTemplateDesigner.Designer;

namespace PrintTemplateDesigner.Printing
{
    public class PrintEngine
    {
        private Template template;
        private DataSourceManager dataSourceManager;
        private PrintDocument printDocument;
        private int currentRecordIndex = 0;
        private List<Dictionary<string, object>> dataRecords;
        
        public PrintEngine(Template template, DataSourceManager dataSourceManager)
        {
            this.template = template;
            this.dataSourceManager = dataSourceManager;
            
            printDocument = new PrintDocument();
            printDocument.PrintPage += PrintDocument_PrintPage;
            printDocument.EndPrint += PrintDocument_EndPrint;
            
            // 设置打印机
            if (!string.IsNullOrEmpty(template.PrinterName))
            {
                printDocument.PrinterSettings.PrinterName = template.PrinterName;
            }
            
            printDocument.PrinterSettings.Copies = (short)template.Copies;
            printDocument.DefaultPageSettings.Landscape = template.Landscape;
        }
        
        public void Print()
        {
            // 加载数据
            LoadData();
            
            if (dataRecords == null || dataRecords.Count == 0)
            {
                // 无数据源,直接打印模板
                dataRecords = new List<Dictionary<string, object>> { new Dictionary<string, object>() };
            }
            
            currentRecordIndex = 0;
            printDocument.Print();
        }
        
        public void PrintPreview()
        {
            PrintPreviewDialog preview = new PrintPreviewDialog
            {
                Document = printDocument
            };
            preview.ShowDialog();
        }
        
        private void LoadData()
        {
            if (template.DataSourceType == "None" || string.IsNullOrEmpty(template.Query))
            {
                dataRecords = new List<Dictionary<string, object>> { new Dictionary<string, object>() };
                return;
            }
            
            dataRecords = dataSourceManager.ExecuteQuery(template.Query);
        }
        
        private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            Graphics g = e.Graphics;
            g.PageUnit = GraphicsUnit.Millimeter;
            
            // 设置页面边距
            float leftMargin = template.MarginLeft;
            float topMargin = template.MarginTop;
            
            // 获取当前记录数据
            Dictionary<string, object> record = dataRecords[currentRecordIndex];
            
            // 绘制所有元素
            foreach (var elemData in template.Elements)
            {
                ElementBase element = ElementFactory.CreateElement(elemData.Type);
                element.LoadFromData(elemData);
                
                // 替换数据字段
                ReplaceDataFields(element, record);
                
                // 绘制元素
                element.Draw(g, false);
            }
            
            // 判断是否还有更多页
            currentRecordIndex++;
            e.HasMorePages = currentRecordIndex < dataRecords.Count;
        }
        
        private void PrintDocument_EndPrint(object sender, PrintEventArgs e)
        {
            currentRecordIndex = 0;
        }
        
        private void ReplaceDataFields(ElementBase element, Dictionary<string, object> record)
        {
            if (string.IsNullOrEmpty(element.DataField)) return;
            
            if (record.ContainsKey(element.DataField))
            {
                object value = record[element.DataField];
                string formattedValue = FormatValue(value, element.Format);
                
                if (element is TextElement textElem)
                {
                    textElem.Text = formattedValue;
                }
                else if (element is BarcodeElement barcodeElem)
                {
                    barcodeElem.BarcodeData = formattedValue;
                }
                // 其他元素类型...
            }
        }
        
        private string FormatValue(object value, string format)
        {
            if (value == null) return "";
            
            if (string.IsNullOrEmpty(format))
            {
                return value.ToString();
            }
            
            if (value is DateTime dateTime)
            {
                return dateTime.ToString(format);
            }
            else if (value is decimal decimalValue)
            {
                return decimalValue.ToString(format);
            }
            else if (value is double doubleValue)
            {
                return doubleValue.ToString(format);
            }
            else if (value is int intValue)
            {
                return intValue.ToString(format);
            }
            
            return value.ToString();
        }
    }
}

9. 项目文件 (PrintTemplateDesigner.csproj)

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{YOUR-PROJECT-GUID}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <RootNamespace>PrintTemplateDesigner</RootNamespace>
    <AssemblyName>PrintTemplateDesigner</AssemblyName>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
    <Reference Include="System.Configuration" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="MainForm.cs" />
    <Compile Include="MainForm.Designer.cs" />
    <Compile Include="Designer\DesignSurface.cs" />
    <Compile Include="Designer\ElementBase.cs" />
    <Compile Include="Designer\TextElement.cs" />
    <Compile Include="Designer\ImageElement.cs" />
    <Compile Include="Designer\LineElement.cs" />
    <Compile Include="Designer\RectangleElement.cs" />
    <Compile Include="Designer\BarcodeElement.cs" />
    <Compile Include="Designer\TableElement.cs" />
    <Compile Include="Designer\ElementFactory.cs" />
    <Compile Include="PropertyGrid\PropertyGridEx.cs" />
    <Compile Include="PropertyGrid\PropertyItem.cs" />
    <Compile Include="PropertyGrid\PropertyCategory.cs" />
    <Compile Include="DataSource\DataSourceManager.cs" />
    <Compile Include="DataSource\DataTableSource.cs" />
    <Compile Include="DataSource\JsonDataSource.cs" />
    <Compile Include="Printing\PrintEngine.cs" />
    <Compile Include="Printing\PreviewForm.cs" />
    <Compile Include="Printing\PrinterSettings.cs" />
    <Compile Include="Templates\Template.cs" />
    <Compile Include="Templates\TemplateSerializer.cs" />
    <Compile Include="Templates\TemplateManager.cs" />
    <Compile Include="Utils\DragDropManager.cs" />
    <Compile Include="Utils\SelectionManager.cs" />
    <Compile Include="Utils\UndoRedoManager.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

参考代码 Winform可视化打印模板设计 www.youwenfan.com/contentcnv/111994.html

三、使用说明

1. 功能特点

功能 描述
可视化设计 拖拽式设计界面,所见即所得
丰富元素 文本、图片、线条、矩形、条码、二维码、表格
数据源绑定 支持数据库、JSON、XML等多种数据源
打印预览 实时预览打印效果
模板管理 保存/加载模板,模板库管理
撤销重做 完整的操作历史记录
对齐辅助 网格、标尺、吸附对齐

2. 支持的元素类型

  1. 文本元素

    • 支持富文本格式
    • 字体、颜色、对齐方式
    • 自动换行、自动大小
  2. 图片元素

    • 支持多种图片格式
    • 缩放模式(拉伸、保持比例)
    • 透明度设置
  3. 条码/二维码

    • Code128、EAN13、QRCode等
    • 可调节尺寸和纠错级别
  4. 表格元素

    • 动态行数
    • 单元格合并
    • 表头冻结
  5. 线条/矩形

    • 实线、虚线、点线
    • 圆角矩形
    • 渐变填充

3. 使用流程

1. 新建模板 → 设置页面大小(A4/A5/标签纸等)
2. 拖拽元素到设计区域
3. 设置元素属性和数据源绑定
4. 保存模板
5. 打印预览
6. 连接打印机打印

4. 扩展建议

  1. 集成专业条码库

    // 使用 ZXing.NET 生成条码
    var writer = new BarcodeWriter
    {
        Format = BarcodeFormat.CODE_128,
        Options = new Code128EncodingOptions
        {
            Height = 50,
            Width = 200
        }
    };
    Bitmap barcode = writer.Write(data);
    
  2. 添加更多数据源

    • Excel文件
    • CSV文件
    • Web API
    • MQTT消息
  3. 增强打印功能

    • 批量打印
    • 标签连续打印
    • 双面打印
    • 打印队列管理
  4. 模板市场

    • 预置常用模板(快递单、发票、标签等)
    • 在线模板共享

这个设计器可以直接用于:

  • 仓库标签打印
  • 快递面单打印
  • 产品标签打印
  • 票据打印
  • 报表打印
  • 条码标签打印
posted @ 2026-06-08 16:22  yijg9998  阅读(10)  评论(0)    收藏  举报