C#Winform設計的通用標簽設計器


技術看點

  • PropertyGrid的使用
  • 自定義控件的使用
  • 對象序列化成XML
  • GDI+Windows驅動打印

前言

是的,一不小心把公司名稱透露了。索性幫公司打一下廣告。公司(上海易溯信息科技)是中國奶制品行業追溯生產管理方面的龍頭。最近也是准備把業務拓展到東南亞地區,籌備走出國門。由於老系統的Windows驅動打印部分出現打印速度不夠快,繪圖精度不高,標簽設計器簡陋等問題。於是開始了重構,當然只是參考老程序的實現方式,程序是重新實現的。程序是用很零散的空閑時間寫的,效果還需要在項目中實際運用,進行檢驗。

設計

由於一發現不熟悉的技術點就上網搜索,其實大部分技術難題都是搜索解決的。這里就不申明版權問題了,“如有雷同,純屬意外!”。哈哈

運行時讀取模板數據,模板里標簽的元素的設計

設計時可視化自定義控件的設計類圖

編碼實現

1)PropertyGrid的使用

代碼都來自網絡,主要就是屬性名使用中文。使用英文對實施的電器工程師來說不太友好。

public delegate void PropertyChanged(object Value);
    /// <summary>
    /// 主要是實現中文化屬性顯示
    /// </summary>
    public class PropertyBase : ICustomTypeDescriptor
    {
        AttributeCollection ICustomTypeDescriptor.GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }
        string ICustomTypeDescriptor.GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }
        string ICustomTypeDescriptor.GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }
        TypeConverter ICustomTypeDescriptor.GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }
        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }
        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
        {
            return null;
        }
        object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
        {
            return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
        }
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
        {
            ArrayList props = new ArrayList();
            Type thisType = this.GetType();
            PropertyInfo[] pis = thisType.GetProperties();
            foreach (PropertyInfo p in pis)
            {
                if (p.DeclaringType == thisType || p.PropertyType.ToString() == "System.Drawing.Color")
                {
                    //判斷屬性是否顯示
                    BrowsableAttribute Browsable = (BrowsableAttribute)Attribute.GetCustomAttribute(p, typeof(BrowsableAttribute));
                    if (Browsable != null)
                    {
                        if (Browsable.Browsable == true || p.PropertyType.ToString() == "System.Drawing.Color")
                        {
                            PropertyStub psd = new PropertyStub(p, attributes);
                            props.Add(psd);
                        }
                    }
                    else
                    {
                        PropertyStub psd = new PropertyStub(p, attributes);
                        props.Add(psd);
                    }
                }
            }
            PropertyDescriptor[] propArray = (PropertyDescriptor[])props.ToArray(typeof(PropertyDescriptor));
            return new PropertyDescriptorCollection(propArray);
        }
        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }
    }

    /// <summary>
    /// 自定義屬性攔截器
    /// </summary>
    public class PropertyStub : PropertyDescriptor
    {
        PropertyInfo info;
        public PropertyStub(PropertyInfo propertyInfo, Attribute[] attrs)
            : base(propertyInfo.Name, attrs)
        {
            info = propertyInfo;
        }
        public override Type ComponentType
        {
            get { return info.ReflectedType; }
        }
        public override bool IsReadOnly
        {
            get { return info.CanWrite == false; }
        }
        public override Type PropertyType
        {
            get { return info.PropertyType; }
        }
        public override bool CanResetValue(object component)
        {
            return false;
        }
        public override object GetValue(object component)
        {
            try
            {
                return info.GetValue(component, null);
            }
            catch
            {
                return null;
            }
        }
        public override void ResetValue(object component)
        {
        }
        public override void SetValue(object component, object value)
        {
            info.SetValue(component, value, null);
        }
        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
        //通過重載下面這個屬性,可以將屬性在PropertyGrid中的顯示設置成中文
        public override string DisplayName
        {
            get
            {
                if (info != null)
                {
                    ChnPropertyAttribute uicontrolattibute = (ChnPropertyAttribute)Attribute.GetCustomAttribute(info, typeof(ChnPropertyAttribute));
                    if (uicontrolattibute != null)
                        return uicontrolattibute.PropertyName;
                    else
                    {
                        return info.Name;
                    }
                }
                else
                    return "";
            }
        }

        public override string Description
        {
            get
            {
                if (info != null)
                {
                    ChnPropertyAttribute uicontrolattibute = (ChnPropertyAttribute)Attribute.GetCustomAttribute(info, typeof(ChnPropertyAttribute));
                    if (uicontrolattibute != null)
                        return uicontrolattibute.PropertyDescription;
                }
                return string.Empty;
            }
        }
    }
自定義屬性攔截器
/// <summary>
    /// 中文方式自定義屬性標識
    /// </summary>
    public class ChnPropertyAttribute : Attribute
    {
        private string _PropertyName;
        private string _PropertyDescription;
        
        public ChnPropertyAttribute(string Name, string Description)
        {
            _PropertyName = Name;
            _PropertyDescription = Description;
        }
        public ChnPropertyAttribute(string Name)
        {
            _PropertyName = Name;
            _PropertyDescription = "";
        }
        public string PropertyName
        {
            get { return _PropertyName; }
        }
        public string PropertyDescription
        {
            get { return _PropertyDescription; }
        }
    }
自定義中文屬性的Attribute

實際使用中文屬性

2)自定義控件的使用

/// <summary>
    /// 標簽最頂層容器,標簽設計時容器
    /// </summary>
    [Serializable]
    public partial class RadiusRectangleSharp : Panel
    {
        #region 鼠標移動和縮放       
        const int Band = 5;
        const int MinWidth = 10;
        const int MinHeight = 10;
        private EnumMousePointPosition _mMousePointPosition;
        private Point _p, _p1;
        private EnumMousePointPosition MousePointPosition(Size size, System.Windows.Forms.MouseEventArgs e)
        {

            if ((e.X >= -1 * Band) | (e.X <= size.Width) | (e.Y >= -1 * Band) | (e.Y <= size.Height))
            {
                if (e.X < Band)
                {
                    if (e.Y < Band) { return EnumMousePointPosition.MouseSizeTopLeft; }
                    else
                    {
                        if (e.Y > -1 * Band + size.Height)
                        { return EnumMousePointPosition.MouseSizeBottomLeft; }
                        else
                        { return EnumMousePointPosition.MouseSizeLeft; }
                    }
                }
                else
                {
                    if (e.X > -1 * Band + size.Width)
                    {
                        if (e.Y < Band)
                        { return EnumMousePointPosition.MouseSizeTopRight; }
                        else
                        {
                            if (e.Y > -1 * Band + size.Height)
                            { return EnumMousePointPosition.MouseSizeBottomRight; }
                            else
                            { return EnumMousePointPosition.MouseSizeRight; }
                        }
                    }
                    else
                    {
                        if (e.Y < Band)
                        { return EnumMousePointPosition.MouseSizeTop; }
                        else
                        {
                            if (e.Y > -1 * Band + size.Height)
                            { return EnumMousePointPosition.MouseSizeBottom; }
                            else
                            { return EnumMousePointPosition.MouseDrag; }
                        }
                    }
                }
            }
            else
            { return EnumMousePointPosition.MouseSizeNone; }
        }
        #endregion               
        #region Local Variables       
        private Color _borderColor = Color.White;
        private int _radius = 8;
        private int _opacity = 68;
        private Color _dimmedColor = Color.LightGray;
        protected Rectangle IRect = new Rectangle();
        #endregion
        #region Properties        
        public Color BorderColor
        {
            get { return _borderColor; }
            set { _borderColor = value; Invalidate(); }
        }
        public int Opacity
        {
            get { return _opacity; }
            set { _opacity = value; this.Invalidate(); }
        }      
        public int Radius
        {
            get { return _radius; }
            set { _radius = value; this.Invalidate(); }
        }
        /// <summary>
        /// 當前模板信息
        /// </summary>
        public TemplateItemInfo CurrentTemplateInfo
        {
            get
            {
                return _currentTempletInfo;
            }
            set
            {
                _currentTempletInfo = value;
            }
        }
        private TemplateItemInfo _currentTempletInfo = new TemplateItemInfo();
        #endregion        
        public RadiusRectangleSharp()
        {
            InitializeComponent();
            AllowDrop = true;
            BackColor = Color.White;
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.Opaque, true);
            Margin = new Padding(1, 1, 1, 1);
            Padding = new Padding(0, 0, 0, 0);
            BorderColor = Color.DarkBlue;
            UpdateStyles();
            SendToBack();
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            SmoothingMode sm = e.Graphics.SmoothingMode;
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            e.Graphics.Clear(Color.White);
            DrawBorder(e.Graphics);
            DrawBackground(e.Graphics);
            e.Graphics.SmoothingMode = sm;
        }
        protected void DrawBorder(Graphics g)
        {
            Rectangle rect = ClientRectangle;
            rect.Width--;
            rect.Height--;
            using (GraphicsPath bp = GetPath(rect, _radius))
            {
                using (Pen p = new Pen(_borderColor))
                {
                    g.DrawPath(p, bp);
                }
            }
        }
        protected void DrawBackground(Graphics g)
        {
            Rectangle rect = ClientRectangle;
            IRect = rect;
            rect.X++;
            rect.Y++;
            rect.Width -= 2;
            rect.Height -= 2;
            using (GraphicsPath bb = GetPath(rect, _radius))
            {
                using (Brush br = new SolidBrush(Color.FromArgb(_opacity, BackColor)))
                {
                    g.FillPath(br, bb);
                }
            }
        }
        protected GraphicsPath GetPath(Rectangle rc, int r)
        {
            int x = rc.X, y = rc.Y, w = rc.Width, h = rc.Height;
            r = r << 1;
            GraphicsPath path = new GraphicsPath();
            if (r > 0)
            {
                if (r > h) { r = h; };                              //Rounded
                if (r > w) { r = w; };                              //Rounded
                path.AddArc(x, y, r, r, 180, 90);                    //Upper left corner
                path.AddArc(x + w - r, y, r, r, 270, 90);            //Upper right corner
                path.AddArc(x + w - r, y + h - r, r, r, 0, 90);        //Lower right corner
                path.AddArc(x, y + h - r, r, r, 90, 90);            //Lower left corner
                path.CloseFigure();
            }
            else
            {
                path.AddRectangle(rc);
            }
            return path;
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            _p.X = e.X;
            _p.Y = e.Y;
            _p1.X = e.X;
            _p1.Y = e.Y;
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            _mMousePointPosition = EnumMousePointPosition.MouseSizeNone;
            this.Cursor = Cursors.Arrow;
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                //本控件是頂層容器,不允許位移
                switch (_mMousePointPosition)
                {
                    #region 位置計算
                    case EnumMousePointPosition.MouseDrag:
                        break;
                    case EnumMousePointPosition.MouseSizeBottom:
                        Height = Height + e.Y - _p1.Y;
                        _p1.X = e.X;
                        _p1.Y = e.Y; //'記錄光標拖動的當前點    
                        break;
                    case EnumMousePointPosition.MouseSizeBottomRight:
                        Width = Width + e.X - _p1.X;
                        Height = Height + e.Y - _p1.Y;
                        _p1.X = e.X;
                        _p1.Y = e.Y; //'記錄光標拖動的當前點    
                        break;
                    case EnumMousePointPosition.MouseSizeRight:
                        Width = Width + e.X - _p1.X;
                        Height = Height + e.Y - _p1.Y;
                        _p1.X = e.X;
                        _p1.Y = e.Y; //'記錄光標拖動的當前點    
                        break;
                    case EnumMousePointPosition.MouseSizeTop:
                        Height = Height - (e.Y - _p.Y);
                        break;
                    case EnumMousePointPosition.MouseSizeLeft:
                        Width = Width - (e.X - _p.X);
                        break;
                    case EnumMousePointPosition.MouseSizeBottomLeft:
                        Width = Width - (e.X - _p.X);
                        Height = Height + e.Y - _p1.Y;
                        _p1.X = e.X;
                        _p1.Y = e.Y; //'記錄光標拖動的當前點    
                        break;
                    case EnumMousePointPosition.MouseSizeTopRight:
                        Width = Width + (e.X - _p1.X);
                        Height = Height - (e.Y - _p.Y);
                        _p1.X = e.X;
                        _p1.Y = e.Y; //'記錄光標拖動的當前點    
                        break;
                    case EnumMousePointPosition.MouseSizeTopLeft:
                        Width = Width - (e.X - _p.X);
                        Height = Height - (e.Y - _p.Y);
                        break;
                    default:
                        break;
                        #endregion
                }
                if (Width < MinWidth) Width = MinWidth;
                if (Height < MinHeight) Height = MinHeight;
            }
            else
            {
                _mMousePointPosition = MousePointPosition(Size, e);
                switch (_mMousePointPosition)
                {
                    #region 改變光標
                    case EnumMousePointPosition.MouseSizeNone:
                        this.Cursor = Cursors.Arrow;        //'箭頭    
                        break;
                    case EnumMousePointPosition.MouseDrag:
                        this.Cursor = Cursors.SizeAll;      //'四方向    
                        break;
                    case EnumMousePointPosition.MouseSizeBottom:
                        this.Cursor = Cursors.SizeNS;       //'南北    
                        break;
                    case EnumMousePointPosition.MouseSizeTop:
                        this.Cursor = Cursors.SizeNS;       //'南北    
                        break;
                    case EnumMousePointPosition.MouseSizeLeft:
                        this.Cursor = Cursors.SizeWE;       //'東西    
                        break;
                    case EnumMousePointPosition.MouseSizeRight:
                        this.Cursor = Cursors.SizeWE;       //'東西    
                        break;
                    case EnumMousePointPosition.MouseSizeBottomLeft:
                        this.Cursor = Cursors.SizeNESW;     //'東北到南西    
                        break;
                    case EnumMousePointPosition.MouseSizeBottomRight:
                        this.Cursor = Cursors.SizeNWSE;     //'東南到西北    
                        break;
                    case EnumMousePointPosition.MouseSizeTopLeft:
                        this.Cursor = Cursors.SizeNWSE;     //'東南到西北    
                        break;
                    case EnumMousePointPosition.MouseSizeTopRight:
                        this.Cursor = Cursors.SizeNESW;     //'東北到南西    
                        break;
                    default:
                        break;
                        #endregion
                }
            }
        }
        protected override void OnResize(EventArgs eventargs)
        {
            if (CurrentTemplateInfo != null)
            {
                CurrentTemplateInfo.Width = Size.Width;
                CurrentTemplateInfo.Height = Size.Height;
                Invalidate();
            }
        }
        protected override void OnDragEnter(DragEventArgs drgevent)
        {
            drgevent.Effect = DragDropEffects.Copy;
            base.OnDragEnter(drgevent);
        }
        protected override void OnDragDrop(DragEventArgs drgevent)
        {
            try
            {
                string[] strs = (string[])drgevent.Data.GetData(typeof(string[])); //獲取拖拽數據
                PictureBox ctrl = null;
                #region 實例化元素控件
                switch (strs.FirstOrDefault())
                {
                    case "Barcode":
                        ctrl = new BarcodePictureBox();
                        break;
                    case "Image":
                        ctrl = new ImagePictureBox();
                        break;
                    case "Text":
                        ctrl = new StaticTextBox();
                        break;
                    default:
                        break;
                }
                #endregion
                ctrl.Location = PointToClient(new Point(drgevent.X, drgevent.Y)); //屏幕坐標轉換成控件容器坐標 
                ctrl.BringToFront();
                Controls.Add(ctrl);
            }
            catch (Exception ex)
            {
                string msg = "初始化控件出錯!錯誤碼:" + ex.Message + Environment.NewLine + ex.StackTrace;
                MessageTip.ShowError(this, msg, 3000);
            }
            base.OnDragDrop(drgevent);
        }
    }

整體上來說就是GDI+的使用,其中用了Base64編碼來序列化圖片。

3)對象序列化成XML

使用的是標准的方式:

/// <summary>
        /// 把對象序列化成xml文件
        /// </summary>
        /// <typeparam name="T">對象的類</typeparam>
        /// <param name="outFile">輸出的文件和路徑</param>
        /// <param name="t">對象的實例</param>
        public static void SerializerToXML<T>(string outFile, T t) where T : class
        {
            using (System.IO.FileStream fs = new System.IO.FileStream(outFile, System.IO.FileMode.Create))
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
                XmlSerializer xs = new XmlSerializer(typeof(T));
                xs.Serialize(fs, t, ns);
                fs.Flush();
            }
        }

        /// <summary>
        /// 從XML文件反序列化成集合對象
        /// </summary>
        /// <typeparam name="T">對象</typeparam>
        /// <param name="inXMLFile">xml的文件,全路徑</param>
        /// <returns>對象集合</returns>
        public static T LoadFromXML<T>(string inXMLFile) where T : class
        {
            var t = default(T);
            using (System.IO.FileStream fs = new System.IO.FileStream(inXMLFile, System.IO.FileMode.Open))
            {
                XmlSerializer xs = new XmlSerializer(typeof(T));
                t = (T)xs.Deserialize(fs);
                fs.Close();
            }
            return t;
        }
 /// <summary>
    /// 圖形元素
    /// </summary>
    [Serializable]
    public class ImageElementNode : PropertyBase, IElementNodeData, INotifyPropertyChanged
    {
        protected PictureBoxSizeMode _PictureBoxSizeMode = PictureBoxSizeMode.StretchImage;
        [ChnProperty("縮放模式", "圖片原始尺寸和元素大小不一致時需要對原始圖片進行縮放,設置縮放模式。")]
        [Category("通用屬性")]
        public PictureBoxSizeMode ImageBoxSizeMode
        {
            get { return _PictureBoxSizeMode; }
            set { _PictureBoxSizeMode = value; }
        }

        private Point _location;
        [ChnProperty("位置", "節點元素的在模板里的位置的坐標,鼠標選中節點即可以移動位置。")]
        [Category("通用屬性")]
        public Point Location
        {
            get { return _location; }
            set { _location = value; }
        }

        private string _name;
        [ChnProperty("元素名稱", "一般自動生成,不需要維護。")]
        [Category("通用屬性")]
        [XmlAttribute("Name")]
        public string Name
        {
            get { return _name; }
            set { _name = value; NotifyPropertyChanged("Name"); }
        }

        [ChnProperty("元素節點類型", "模板元素節點類型,元素產生時根據添加時自動確定,設計時不要修改類型。"), Category("通用屬性")]
        [XmlAttribute("NodeCategory")]
        public ElementNodeCategory NodeCategory
        {
            get { return ElementNodeCategory.靜態文本; }
        }

        private ImageRoteType _roteDescription = ImageRoteType.正常;
        [ChnProperty("旋轉角度", "變形的形態描述,比如順時針旋轉90度。"), Category("通用屬性")]
        public ImageRoteType RoteDescription
        {
            get { return _roteDescription; }
            set { _roteDescription = value; NotifyPropertyChanged("RoteDescription"); }
        }

        private Size _size;
        [ChnProperty("元素大小", "包括高度和寬度,單位是像素。使用鼠標可調節大小,滾輪進行縮放。"), Category("通用屬性")]
        public Size Size
        {
            get { return _size; }
            set { _size = value; }
        }

        [ChnProperty("靜態表達式", @"可以從‘ProductName,ProductCode,ProductSpec,
                       CorpCode,BatchCode,LineCode,DepartCode,TeamCode,WorkerCode,
                       PackDate,ValidateDate,ProductFullName,CustomerCode,CustomerName’字段中獲取值。"),
         Category("表達式")]
        public StaticMapProperty StaticMapProperty { get; set; }
        [ChnProperty("動態表達式", @"可以從‘Code,EncryptCode,ParentCode,CipherFieldCode,Seqence,
                                   VersionCode,VersionName,BatchCode,CorpCode,LineCode,PackDate,ProductCode,WorkPointInt,
                                   WorkPointAZ,Dynamic,’字段中獲取值。"),
         Category("表達式")]
        public DynamicMapProperty DynamicMapProperty { get; set; }

        private string text;
        [ChnProperty("固定字符", "在不寫任何表達式的情況下設置的固定字符"), Category("通用屬性")]
        [XmlAttribute("Text")]
        public string Text
        {
            get { return text; }
            set { text = value; NotifyPropertyChanged("Text"); }
        }

        private string _動態內容;
        [ChnProperty("動態內容", @"格式:{PropertyName[(Start[,Length])]}[&Blank[(Length)]]&{PropertyName[(Start[,Length])]} 
                                    PropertyName:動態屬性里的選項
                                    Start:動態屬性對應內容的開始位置
                                    Length:截取內容的長度
                                    Blank:空格
                                    Length:空格的個數
                                    &:為分隔符
                                    設置此內容的時候,請務必小心,設置時系統不檢測其值的合法性,在執行的時候可能會報錯"), Category("表達式")]
        public string 動態內容
        {
            get { return _動態內容; }
            set { _動態內容 = value; NotifyPropertyChanged("動態內容"); }
        }
        [ChnProperty("圖形數據", "Base64編碼的圖形數據,縮放后序列化的字節碼。雙擊圖像元素進行選擇和預覽。"), Category("圖形屬性")]

        private string _imageData;
        [Browsable(false)]
        public string BinaryData
        {
            get { return _imageData; }
            set { _imageData = value; NotifyPropertyChanged("BinaryData"); }
        }

        private string _formatString = string.Empty;
        [ChnProperty("格式掩碼", "如yyyyMMdd,HH:MM:SS。"), Category("表達式")]
        public string FormatString
        {
            get
            {
                return _formatString;
            }
            set
            {
                _formatString = value;
                NotifyPropertyChanged("FormatString");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public Image GetElmentNodeImage(PrintData data)
        {
            if (string.IsNullOrEmpty(BinaryData))
                throw new Exception("圖片元素沒有綁定圖片資源!");
            Bitmap bmp = new Bitmap(Size.Width-3, Size.Height-3);
            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.White);
            g.SmoothingMode = SmoothingMode.HighQuality;
            byte[] arr = Convert.FromBase64String(BinaryData);
            using (MemoryStream ms = new MemoryStream(arr))
            {
                Bitmap tempBmp = new Bitmap(ms);
                using (PictureBox pb = new PictureBox())
                {
                    pb.Size = Size;
                    pb.SizeMode = ImageBoxSizeMode;
                    pb.Image = tempBmp;
                    return ImageRote.RoteImage(RoteDescription, pb.Image);
                } 
            } 
        }

        private void NotifyPropertyChanged(string property)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
        }

        public ImageElementNode()
        {
            StaticMapProperty = StaticMapProperty.None;
            DynamicMapProperty = DynamicMapProperty.None;
            動態內容 = "";
        } 
    }

4)GDI+Windows驅動打印

/// <summary>
    /// GDI Printer驅動類
    /// </summary>
    public class CoolGDIPrinter : WindowsVirtualPrinter
    {
        protected PrintDocument printDocument;
        protected Dictionary<string, TemplateItemInfo> dict = new Dictionary<string, TemplateItemInfo>();
        private object printSync = new object();
        private string templateFile = AppDomain.CurrentDomain.BaseDirectory + "Config\\GDITemplate.Config";
        private string current_data = string.Empty;
        private PrintData pd = null;
        private string current_Template = string.Empty;
        public CoolGDIPrinter(HardwarePort port, ILog log) : base(port, log)
        {
            if (!System.IO.File.Exists(templateFile))
            {
                throw new Exception(string.Format("模板文件{0}不存在!", templateFile));
            }
            DataList<TemplateItemInfo> list = WinFormHelper.LoadFromXML<DataList<TemplateItemInfo>>(templateFile);
            if (list != null && list.Count > 0)
            {
                foreach (TemplateItemInfo template in list)
                {
                    dict.Add(template.Code, template);
                }
            }
            if (string.IsNullOrEmpty(port.PortName))
            {
                throw new Exception("打印機名稱不能為空!");
            }
            var findPrinter = GetAllLocalPrinters().Find(obj => obj.Contains(port.PortName));
            if (string.IsNullOrEmpty(findPrinter))
            {
                throw new Exception(string.Format("本地沒有打印機{0},請檢查打印機驅動是否正確安裝。", port.PortName));
            }
            if (dict.Count == 0)
            {
                throw new Exception(string.Format("模板文件{0}內容為空,或者格式不符!", templateFile));
            }
            #region PrintDocument
            printDocument = new PrintDocument
            {
                PrinterSettings =
                {
                    PrinterName = PortName,
                }
            };
            printDocument.PrintController = new StandardPrintController();
            printDocument.BeginPrint += PrintDocument_BeginPrint;
            printDocument.PrintPage += PrintDocument_PrintPage;
            printDocument.EndPrint += PrintDocument_EndPrint;
            #endregion
            var isvali = printDocument.PrinterSettings.IsValid;
            if (!isvali)
            {
                throw new Exception(string.Format("沒有指定有效的打印機,{0}不可用!", PortName));
            }           
        }
        /// <summary>
        /// 獲取本機所有打印機列表
        /// </summary>
        /// <returns>本機所有打印機列表</returns>
        private List<string> GetAllLocalPrinters()
        {
            var fPrinters = new List<string>();
            foreach (string fPrinterName in PrinterSettings.InstalledPrinters)
            {
                if (!fPrinters.Contains(fPrinterName))
                {
                    fPrinters.Add(fPrinterName);
                }
            }
            return fPrinters;
        }
        /// <summary>
        /// 獲取打印機的當前狀態
        /// </summary>
        /// <param name="PrinterDevice">打印機設備名稱</param>
        /// <returns>打印機狀態</returns>
        private PrinterStatus GetPrinterStat(string PrinterDevice)
        {
            PrinterStatus ret = 0;
            string path = @"win32_printer.DeviceId='" + PrinterDevice + "'";
            ManagementObject printerMgrObj = new ManagementObject(path);
            printerMgrObj.Get();
            ret = (PrinterStatus)Convert.ToInt32(printerMgrObj.Properties["PrinterStatus"].Value);
            return ret;
        }
        /// <summary>
        /// WMI檢測指定的打印機是否可用
        /// </summary>
        /// <param name="printerNameIn">指定的打印機名稱</param>
        /// <returns></returns>
        protected bool CheckPrinter(string printerNameIn)
        {
            var scope = new ManagementScope(@"\root\cimv2");
            scope.Connect();
            ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer");
            string printerName = "";
            foreach (ManagementObject printer in searcher.Get())
            {
                printerName = printer["Name"].ToString().ToLower();
                if (printerName.IndexOf(printerNameIn.ToLower()) > -1)
                {
                    if (printer["WorkOffline"].ToString().ToLower().Equals("true"))
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        private object printlock = new object();
        /// <summary>
        /// 內部執行打印
        /// </summary>
        /// <param name="data"></param>
        /// <param name="templateKey"></param>
        protected override void WritePrinter(PrintData data, string templateKey)
        {
            var template = dict[templateKey];
            if (template == null)
            {
                throw new Exception(string.Format("不存在打印機模板[{0}]的配置文件", templateKey));
            }
            lock (printlock)
            {
                try
                {
                    printDocument.PrinterSettings.Copies = (short)template.Quantity;
                    printDocument.PrinterSettings.DefaultPageSettings.PaperSize = new PaperSize("GDI_LableSize", template.Width + 2, template.Height + 2);
                    printDocument.OriginAtMargins = true;
                    printDocument.DefaultPageSettings.Margins = new Margins(2, 2, 2, 2);
                    var printerIsonline = CheckPrinter(printDocument.PrinterSettings.PrinterName);
                    if (!printerIsonline)
                    {
                        RaiseException(new Exception(string.Format("打印機狀態{0},請稍候進行打印!", "離線,請檢查打印機是否正常開啟")));
                        return;
                    }
                    current_data = data.Code;
                    pd = data;
                    current_Template = templateKey;
                    PostData(data);
                    printDocument.Print();
                }
                catch (Exception ex)
                {
                    RaiseReceived(ex, null);
                    RaiseException(new Exception(current_data + "打印失敗,原因:" + ex.Message));
                }
            }
        }
        /// <summary>
        /// 外部調用驅動程序,發送打印數據
        /// </summary>
        /// <param name="data">打印數據</param>
        /// <param name="templateKey">模板鍵</param>
        public override void WriteData(PrintData data, string templateKey)
        {
            base.WriteData(data, templateKey);
            IsPrinting = true;
            WritePrinter(data, templateKey);
            IsPrinting = false;
        }
        /// <summary>
        /// 啟動生成標簽圖形
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PrintDocument_BeginPrint(object sender, PrintEventArgs e)
        {
            Log.Info(string.Format("開始打印數據:[{0}],[{1}]", PortName, current_data));
        }
        /// <summary>
        /// 執行標簽圖形生成產生畫布
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            lock (printSync)
            {
                try
                {
                    var imgData = BuildTemplateImage(pd, current_Template);
                    if (imgData != null)
                    {
                        e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                        e.Graphics.DrawImage(imgData, 0, 0, imgData.Width, imgData.Height);
                        if (IsDebug)
                        {
                            string debugPath = AppDomain.CurrentDomain.BaseDirectory + "output";
                            if (!System.IO.Directory.Exists(debugPath))
                            {
                                System.IO.Directory.CreateDirectory(debugPath);
                            }
                            string bmpFile = System.IO.Path.Combine(debugPath, current_data + DateTime.Now.Ticks + ".PNG");
                            imgData.Save(bmpFile, ImageFormat.Png);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex);
                    throw new Exception("構建標簽圖形失敗,錯誤描述:" + ex.Message + Environment.NewLine + ex.StackTrace);
                }
            }
        }
        /// <summary>
        /// 結束打印繪圖,發送給打印機打印數據
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PrintDocument_EndPrint(object sender, PrintEventArgs e)
        {
            Log.Info(string.Format("[{0}],[{1}],發送打印數據完成", PortName, current_data));
        }
        /// <summary>
        /// 內部通過模板生成圖形
        /// </summary>
        /// <param name="data"></param>
        /// <param name="templateKey"></param>
        /// <returns></returns>
        protected override Bitmap BuildTemplateImage(PrintData data, string templateKey)
        {
            var template = dict[templateKey];
            Bitmap bmp = new Bitmap(template.Width, template.Height);
            Graphics graphics = Graphics.FromImage(bmp);
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.Clear(Color.White);
            //1、畫圖片元素節點
            foreach (var bmpElement in template.ImageElementList)
            {
                Rectangle rect = new Rectangle(bmpElement.Location.X, bmpElement.Location.Y, bmpElement.Size.Width, bmpElement.Size.Height);
                graphics.DrawImage(bmpElement.GetElmentNodeImage(data), rect);
            }
            //2、畫條碼元素節點
            foreach (var barcodeElement in template.BarcodeElementList)
            {
                Rectangle rect = new Rectangle(barcodeElement.Location.X, barcodeElement.Location.Y, barcodeElement.Size.Width, barcodeElement.Size.Height);
                graphics.DrawImage(barcodeElement.GetElmentNodeImage(data), rect);
            }
            //3、畫靜態文本元素節點
            foreach (var txtElement in template.TextBoxList)
            {
                Rectangle rect = new Rectangle(txtElement.Location.X, txtElement.Location.Y, txtElement.Size.Width, txtElement.Size.Height);
                graphics.DrawImage(txtElement.GetElmentNodeImage(data), rect);
            }
            return bmp;
        }
    }

PrintDocument對象就是對打印機畫布進行的封裝,主要就是GDI+的操作了。

成果物

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM