CompositionDesigner.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / WinForms / System / WinForms / Design / CompositionDesigner.cs / 1 / CompositionDesigner.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
* Copyright (c) 1999, Microsoft Corporation. All Rights Reserved. 
* Information Contained Herein is Proprietary and Confidential.
*/ 
namespace System.Windows.Forms.Design {

    using System.Design;
    using System.Runtime.InteropServices; 
    using System.ComponentModel;
    using System.Diagnostics; 
    using System; 
    using System.ComponentModel.Design;
    using Microsoft.Win32; 
    using System.Drawing;
    using System.Drawing.Design;
    using System.Collections;
    using System.Windows.Forms; 

    ///  
    ///  
    ///     Provides a root designer implementation for designing components.
    ///  
    public class ComponentDocumentDesigner : ComponentDesigner, IRootDesigner, IToolboxUser, IOleDragClient, ITypeDescriptorFilterService {

        private CompositionUI           compositionUI;        // The UI for our designer
        private CompositionCommandSet   commandSet;           // Our set of menu commands 
        private IEventHandlerService    eventHandlerService;  // The service that handles key and menu events
        private InheritanceService      inheritanceService;   // allows us to support inheritance 
        private SelectionUIService      selectionUIService; 
        private DesignerExtenders       designerExtenders;
 
        private ITypeDescriptorFilterService delegateFilterService;

        private bool                    largeIcons = false;
        private bool                    autoArrange = true; 
        private PbrsForward             pbrsFwd;
 
        ///  
        /// 
        ///    Disposes of the resources (other than memory) used by 
        ///       the .
        /// 
        protected override void Dispose(bool disposing) {
            if (disposing) { 
                IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || host != null, "IDesignerHost not found"); 
 
                if (host != null) {
                    host.RemoveService(typeof(IInheritanceService)); 
                    host.RemoveService(typeof(IEventHandlerService));
                    host.RemoveService(typeof(ISelectionUIService));
                    host.RemoveService(typeof(ComponentTray));
 
                    IComponentChangeService cs = (IComponentChangeService)GetService(typeof(IComponentChangeService));
                    Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || cs != null, "IComponentChangeService not found"); 
                    if (cs != null) { 
                        cs.ComponentAdded -= new ComponentEventHandler(OnComponentAdded);
                        cs.ComponentRemoved -= new ComponentEventHandler(OnComponentRemoved); 
                    }
                }

                if (selectionUIService != null) { 
                    selectionUIService.Dispose();
                    selectionUIService = null; 
                } 

                if (commandSet != null) { 
                    commandSet.Dispose();
                    commandSet = null;
                }
 
                if (this.pbrsFwd != null) {
                    pbrsFwd.Dispose(); 
                    pbrsFwd = null; 
                }
 
                if (compositionUI != null) {
                    compositionUI.Dispose();
                    compositionUI = null;
                } 

                if (designerExtenders != null) { 
                    designerExtenders.Dispose(); 
                    designerExtenders = null;
                } 

                if (inheritanceService != null) {
                    inheritanceService.Dispose();
                    inheritanceService = null; 
                }
            } 
            base.Dispose(disposing); 
        }
 
        /// 
        /// 
        ///    Gets  the control for this designer.
        ///  
        public Control Control {
            get { 
                return compositionUI; 
            }
        } 

        /// 
        /// 
        ///    Indicates whether the tray should auto arrange controls. 
        /// 
        public bool TrayAutoArrange { 
            get { 
                return autoArrange;
            } 

            set {
                autoArrange = value;
                Debug.Assert(compositionUI != null, "UI must be created by now."); 
                compositionUI.AutoArrange = value;
            } 
        } 

        ///  
        /// 
        ///    Indicates whether the tray should contain a large icon.
        /// 
        public bool TrayLargeIcon { 
            get {
                return largeIcons; 
            } 

            set { 
                largeIcons = value;
                Debug.Assert(compositionUI != null, "UI must be created by now.");
                compositionUI.ShowLargeIcons = value;
            } 
        }
 
        ///  
        /// 
        ///    Gets a value indicating whether the specified tool is supported by this 
        ///       designer.
        /// 
        protected virtual bool GetToolSupported(ToolboxItem tool) {
            return true; 
        }
 
        ///  
        /// 
        ///     
        ///       Initializes the designer with the specified component.
        /// 
        public override void Initialize(IComponent component) {
            base.Initialize(component); 

            inheritanceService = new InheritanceService(); 
 
            ISite site = component.Site;
            IContainer container = null; 

            IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
            IExtenderProviderService exps = (IExtenderProviderService)GetService(typeof(IExtenderProviderService));
            if (exps != null) { 
                designerExtenders = new DesignerExtenders(exps);
            } 
 
            Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || host != null, "IDesignerHost not found");
            if (host != null) { 
                eventHandlerService = new EventHandlerService(null);
                selectionUIService = new SelectionUIService(host);

                host.AddService(typeof(IInheritanceService), inheritanceService); 
                host.AddService(typeof(IEventHandlerService), eventHandlerService);
                host.AddService(typeof(ISelectionUIService), selectionUIService); 
 
                compositionUI = new CompositionUI(this, site);
 
                host.AddService(typeof(ComponentTray), compositionUI);

                IComponentChangeService cs = (IComponentChangeService)GetService(typeof(IComponentChangeService));
                Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || cs != null, "IComponentChangeService not found"); 
                if (cs != null) {
                    cs.ComponentAdded += new ComponentEventHandler(OnComponentAdded); 
                    cs.ComponentRemoved += new ComponentEventHandler(OnComponentRemoved); 
                }
 
                // Select this component.
                //
                ISelectionService ss = (ISelectionService)GetService(typeof(ISelectionService));
                if (ss != null) { 
                    ss.SetSelectedComponents(new object[] {component}, SelectionTypes.Auto);
                } 
            } 

            // Set up our menu command set 
            //
            if (site != null) {
                commandSet = new CompositionCommandSet(compositionUI, site);
                container = site.Container; 
            }
 
            this.pbrsFwd = new PbrsForward(compositionUI, site); 

            // Hook up our inheritance service and do a scan for inherited components. 
            //
            inheritanceService.AddInheritedComponents(component, container);

            // Hook yourself up to the ITypeDescriptorFilterService so we can hide the 
            // location property on all components being added to the designer.
            // 
            IServiceContainer serviceContainer = (IServiceContainer)GetService(typeof(IServiceContainer)); 
            if (serviceContainer != null) {
                delegateFilterService = (ITypeDescriptorFilterService)GetService(typeof(ITypeDescriptorFilterService)); 
                if (delegateFilterService != null)
                    serviceContainer.RemoveService(typeof(ITypeDescriptorFilterService));

                serviceContainer.AddService(typeof(ITypeDescriptorFilterService), this); 
            }
        } 
 
        /// 
        ///  
        ///     This provides a view for all controls on the form.
        /// 
        /// 
        ///     This provides a view for all controls on the form. 
        /// 
        private void OnComponentAdded(object sender, ComponentEventArgs ce) { 
            if (ce.Component != Component) { 
                compositionUI.AddComponent(ce.Component);
            } 
        }

        /// 
        ///  
        ///     This provides a view for all controls on the form.
        ///  
        ///  
        ///     This provides a view for all controls on the form.
        ///  
        private void OnComponentRemoved(object sender, ComponentEventArgs ce) {
            compositionUI.RemoveComponent(ce.Component);
        }
 
        /// 
        ///  
        ///     
        ///       Allows a
        ///       designer to filter the set of properties the component 
        ///       it is designing will expose through the TypeDescriptor
        ///       object.
        /// 
        protected override void PreFilterProperties(IDictionary properties) { 
            base.PreFilterProperties(properties);
 
            properties["TrayLargeIcon"] = TypeDescriptor.CreateProperty(this.GetType(), "TrayLargeIcon", typeof(bool), 
                                                               BrowsableAttribute.No,
                                                               DesignOnlyAttribute.Yes, 
                                                               CategoryAttribute.Design);
        }

        ///  
        /// 
        ///  
        ///  Indicates whether the 
        /// components can be changed by the designer.
        ///  
        bool IOleDragClient.CanModifyComponents {
            get {
                return(true);
            } 
        }
 
        ///  
        /// 
        ///  
        /// Adds a component to the designer.
        /// 
        bool IOleDragClient.AddComponent(IComponent component, string name, bool firstAdd) {
            IContainer container = Component.Site.Container; 

            if (container != null && name != null && container.Components[name] != null) { 
                name = null; 
            }
 
            IContainer curContainer = null;
            bool reinit = false;

            if (!firstAdd) { 
                if (component.Site != null) {
                    curContainer = component.Site.Container; 
 
                    if (curContainer != container) {
                        curContainer.Remove(component); 
                        reinit = true;
                    }
                }
 
                if (curContainer != container) {
                    container.Add(component, name); 
                } 
            }
            if (reinit) { 
                IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
                if (designerHost != null) {
                    IComponentInitializer init = designerHost.GetDesigner(component) as IComponentInitializer;
                    if (init != null) { 
                        init.InitializeExistingComponent(null);
                    } 
                } 
            }
            return curContainer != container; 
        }

        /// 
        ///  
        /// 
        /// Gets the instance of the control being used to visually represent the specified component. 
        ///  
        Control IOleDragClient.GetControlForComponent(object component) {
            if (compositionUI != null) { 
                return ((IOleDragClient)compositionUI).GetControlForComponent(component);
            }
            return null;
        } 

        ///  
        ///  
        /// 
        ///  Gets the control instance being used 
        /// as the designer surface.
        /// 
        Control IOleDragClient.GetDesignerControl() {
            if (compositionUI != null) { 
                return ((IOleDragClient)compositionUI).GetDesignerControl();
            } 
            return null; 
        }
 
        /// 
        /// 
        /// 
        /// Gets a value indicating if it is valid to drop this type of a component on this client. 
        /// 
        bool IOleDragClient.IsDropOk(IComponent component) { 
            return true; 
        }
 
        /// 
        /// 
        /// 
        /// The list of technologies that this designer can support 
        /// for its view.  Examples of different technologies are
        /// Windows Forms and Web Forms.  Other object models can be 
        /// supported at design time, but they most be able to 
        /// provide a view in one of the supported technologies.
        ///  
        ViewTechnology[] IRootDesigner.SupportedTechnologies {
            get {
                return new ViewTechnology[] {ViewTechnology.Default, (ViewTechnology)1};
            } 
        }
 
        ///  
        /// 
        ///  
        /// The view for this document.  The designer
        /// should assume that the view will be shown shortly
        /// after this call is made and make any necessary
        /// preparations. 
        /// 
 
        //We can live with this one. We have obsoleted some of the enum values. This method 
        //only takes on argument, so it is pretty obvious what argument is bad.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")] 
        object IRootDesigner.GetView(ViewTechnology technology) {
            if (technology != ViewTechnology.Default && technology != (ViewTechnology)1) {
                throw new ArgumentException();
            } 
            return compositionUI;
        } 
 
        /// 
        ///  
        /// 
        /// Gets a value indicating whether the specified tool is supported by this
        /// designer.
        ///  
        bool IToolboxUser.GetToolSupported(ToolboxItem tool) {
            return true; 
        } 

        ///  
        /// 
        /// 
        /// Creates the specified tool.
        ///  
        void IToolboxUser.ToolPicked(ToolboxItem tool) {
            compositionUI.CreateComponentFromTool(tool); 
            IToolboxService toolboxService = (IToolboxService)GetService(typeof(IToolboxService)); 
            if (toolboxService != null) {
                toolboxService.SelectedToolboxItemUsed(); 
            }
        }

        ///  
        /// 
        ///     ITypeDescriptorFilterService implementation. 
        ///  
        /// 
        bool ITypeDescriptorFilterService.FilterAttributes(IComponent component, IDictionary attributes) { 
            if (delegateFilterService != null)
                return delegateFilterService.FilterAttributes(component, attributes);

            return true; 
        }
 
        ///  
        /// 
        ///     ITypeDescriptorFilterService implementation. 
        /// 
        /// 
        bool ITypeDescriptorFilterService.FilterEvents(IComponent component, IDictionary events) {
            if (delegateFilterService != null) 
                return delegateFilterService.FilterEvents(component, events);
 
            return true; 
        }
 
        /// 
        /// 
        ///     ITypeDescriptorFilterService implementation.
        ///  
        /// 
        bool ITypeDescriptorFilterService.FilterProperties(IComponent component, IDictionary properties) { 
            if (delegateFilterService != null) 
                delegateFilterService.FilterProperties(component, properties);
 
            PropertyDescriptor prop;

            string[] noBrowseProps = new string[] {
                "Location", 
            };
 
            prop = (PropertyDescriptor)properties["Location"]; 
            if (prop != null) {
                properties["Location"] = TypeDescriptor.CreateProperty(prop.ComponentType, prop, BrowsableAttribute.No); 
            }

            return true;
        } 

        private class WatermarkLabel : LinkLabel { 
            private CompositionUI compositionUI; 

            public WatermarkLabel(CompositionUI compositionUI) { 
                this.compositionUI = compositionUI;
            }

            protected override void WndProc(ref Message m) { 
                switch (m.Msg) {
                    case NativeMethods.WM_NCHITTEST: 
                        // label returns HT_TRANSPARENT for everything, so all messages get 
                        // routed to the parent.  Change this so we can tell what's going on.
                        // 
                        Point pt = PointToClient(new Point((int)m.LParam));
                        if (PointInLink(pt.X, pt.Y) == null) {
                            m.Result = (IntPtr)NativeMethods.HTTRANSPARENT;
                            break; 
                        }
                        base.WndProc(ref m); 
                        break; 

                    case NativeMethods.WM_SETCURSOR: 
                        if (OverrideCursor == null)
                            compositionUI.SetCursor();
                        else
                            base.WndProc(ref m); 
                        break;
 
                    default: 
                        base.WndProc(ref m);
                        break; 
                }
            }
        }
 
        /// 
        ///  
        ///      The composition UI is the full UI for our composition designer.  We 
        ///      inherit from ComponentTray so we get most of the UI for free.
        ///  
        private class CompositionUI : ComponentTray {

            private WatermarkLabel watermark;
 
            // How high is the top banner in the designer.
            private const int bannerHeight = 40; 
 
            // The width of the border around the client rect.
            private const int borderWidth = 10; 

            private IToolboxService toolboxService;
            private ComponentDocumentDesigner compositionDesigner;
            private IServiceProvider serviceProvider; 

            private SelectionUIHandler      dragHandler; 
 
            /// 
            ///  
            ///      Creates a new CompositionUI object.
            /// 
            public CompositionUI(ComponentDocumentDesigner compositionDesigner, IServiceProvider provider) : base(compositionDesigner, provider) {
                this.compositionDesigner = compositionDesigner; 
                this.serviceProvider = provider;
 
                this.watermark = new WatermarkLabel(this); 
                // VSWhidbey 31825 - LinkLabel has draw problems with fonts < 11 points.
                watermark.Font = new Font(watermark.Font.FontFamily, 11);	 
                watermark.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
                watermark.LinkClicked += new LinkLabelLinkClickedEventHandler(this.OnLinkClick);
                watermark.Dock = System.Windows.Forms.DockStyle.Fill;
                watermark.TabStop = false; 
                watermark.Text = SR.GetString(SR.CompositionDesignerWaterMark);
 
                try { 
                    string link = SR.GetString(SR.CompositionDesignerWaterMarkFirstLink);
                    int wmBegin = watermark.Text.IndexOf(link); 
                    int wmLength = link.Length;
                    watermark.Links.Add(wmBegin, wmLength, "Toolbox");

                    link = SR.GetString(SR.CompositionDesignerWaterMarkSecondLink); 
                    wmBegin = watermark.Text.IndexOf(link);
                    wmLength = link.Length; 
                    watermark.Links.Add(wmBegin, wmLength, "CodeView"); 
                }
                catch (Exception e) { 
                    Debug.WriteLine(e.ToString());
                    if (ClientUtils.IsCriticalException(e)) {
                        throw;
                    } 
                }
 
                catch { 
                }
 
                this.Controls.Add(watermark);
            }

            ///  
            /// 
            ///      Adds a component to the tray. 
            ///  
            public override void AddComponent(IComponent component) {
                base.AddComponent(component); 
                if (Controls.Count > 0) {
                    watermark.Visible = false;
                }
            } 

            protected override bool CanCreateComponentFromTool(ToolboxItem tool) { 
                return true; 
            }
 
            internal override OleDragDropHandler GetOleDragHandler() {
                if (oleDragDropHandler == null) {
                    oleDragDropHandler = new OleDragDropHandler(this.DragHandler, serviceProvider, this);
                } 
                return oleDragDropHandler;
            } 
 
            /// 
            ///  
            ///      Creates a selection UI drag handler for us to use.  You may override
            ///      this if you want to provide different drag semantics.
            /// 
            internal override SelectionUIHandler DragHandler { 
                get {
                    if (dragHandler == null) { 
                        dragHandler = new CompositionSelectionUIHandler(compositionDesigner); 
                    }
                    return dragHandler; 
                }
            }

            private void OnLinkClick(object sender, LinkLabelLinkClickedEventArgs e) { 
                IUIService uis = (IUIService)compositionDesigner.GetService(typeof(IUIService));
                if (uis != null) { 
                    string s = (string)e.Link.LinkData; 
                    if (s == "ServerExplorer")
                        uis.ShowToolWindow(StandardToolWindows.ServerExplorer); 
                    else if (s == "Toolbox")
                        uis.ShowToolWindow(StandardToolWindows.Toolbox);
                    else {
                        Debug.Assert(s == "CodeView", "LinkData unknown: " + s); 
                        IEventBindingService evt = (IEventBindingService)serviceProvider.GetService(typeof(IEventBindingService));
                        if (evt != null) { 
                            evt.ShowCode(); 
                        }
                    } 
                }
            }

            ///  
            /// 
            ///      Sets the cursor.  We override to provide support for the toolbox. 
            ///  
            internal void SetCursor() {
                if (toolboxService == null) { 
                    toolboxService = (IToolboxService)GetService(typeof(IToolboxService));
                }

                if (toolboxService == null || !toolboxService.SetCursor()) { 
                    base.OnSetCursor();
                } 
            } 

            ///  
            /// 
            ///      We don't want to allow drag/drop operations onto the banner area.
            /// 
            protected override void OnDragDrop(DragEventArgs de) { 
                Rectangle clientRect = this.ClientRectangle;
 
                if (clientRect.Contains(this.PointToClient(new Point(de.X, de.Y)))) { 
                    base.OnDragDrop(de);
                    return; 
                }
                else {
                    de.Effect = DragDropEffects.None;
                } 
            }
 
            ///  
            /// 
            ///      We don't want to allow drag/drop operations onto the banner area. 
            /// 
            protected override void OnDragOver(DragEventArgs de) {
                Rectangle clientRect = this.ClientRectangle;
 
                if (clientRect.Contains(this.PointToClient(new Point(de.X, de.Y)))) {
                    base.OnDragOver(de); 
                    return; 
                }
                else { 
                    de.Effect = DragDropEffects.None;
                }
            }
 
            protected override void OnResize(EventArgs e) {
                base.OnResize(e); 
                if (watermark != null) { 
                    watermark.Location = new Point(0, Size.Height/2);
                    watermark.Size = new Size(Width, Size.Height/2); 
                }
            }

            ///  
            /// 
            ///      Sets the cursor.  We override to provide support for the toolbox. 
            ///  
            protected override void OnSetCursor() {
                SetCursor(); 
            }

            /// 
            ///  
            ///      Removes a component from the tray.
            ///  
            public override void RemoveComponent(IComponent component) { 
                base.RemoveComponent(component);
                if (Controls.Count == 1) { 
                    watermark.Visible = true;
                }
            }
 
            /// 
            ///  
            ///      We override the wndproc of the control so we can intercept non client 
            ///      messages.  We create the banner for the composition designer by
            ///      changing the dimensions of the non-client area. 
            /// 
            protected override void WndProc(ref Message m) {
                switch (m.Msg) {
                    default: 
                        base.WndProc(ref m);
 			break; 
                } 
            }
 
            /// 
            /// 
            ///      This class inherits from the abstract SelectionUIHandler
            ///      class to provide a selection UI implementation for the 
            ///      composition designer.
            ///  
            private class CompositionSelectionUIHandler : SelectionUIHandler { 

                private ComponentDocumentDesigner compositionDesigner; 

                /// 
                /// 
                ///      Creates a new selection UI handler for the given 
                ///      composition designer.
                ///  
                public CompositionSelectionUIHandler(ComponentDocumentDesigner compositionDesigner) { 
                    this.compositionDesigner = compositionDesigner;
                } 

                /// 
                /// 
                ///      Retrieves the base component for the selection handler. 
                /// 
                protected override IComponent GetComponent() { 
                    return compositionDesigner.Component; 
                }
 
                /// 
                /// 
                ///      Retrieves the base component's UI control for the selection handler.
                ///  
                protected override Control GetControl() {
                    return compositionDesigner.Control; 
                } 

                ///  
                /// 
                ///      Retrieves the UI control for the given component.
                /// 
                protected override Control GetControl(IComponent component) { 
                    return TrayControl.FromComponent(component);
                } 
 
                /// 
                ///  
                ///      Retrieves the current grid snap size we should snap objects
                ///      to.
                /// 
                protected override Size GetCurrentSnapSize() { 
                    return new Size(8, 8);
                } 
 
                /// 
                ///  
                ///      We use this to request often-used services.
                /// 
                protected override object GetService(Type serviceType) {
                    return compositionDesigner.GetService(serviceType); 
                }
 
                ///  
                /// 
                ///      Determines if the selection UI handler should attempt to snap 
                ///      objects to a grid.
                /// 
                protected override bool GetShouldSnapToGrid() {
                    return false; 
                }
 
                ///  
                /// 
                ///      Given a rectangle, this updates the dimensions of it 
                ///      with any grid snaps and returns a new rectangle.  If
                ///      no changes to the rectangle's size were needed, this
                ///      may return the same rectangle.
                ///  
                public override Rectangle GetUpdatedRect(Rectangle originalRect, Rectangle dragRect, bool updateSize) {
                    Rectangle updatedRect; 
 
                    if (GetShouldSnapToGrid()) {
                        Rectangle newRect = dragRect; 

                        int left = dragRect.X;
                        int top = dragRect.Y;
                        int right = dragRect.X + dragRect.Width; 
                        int bottom = dragRect.Y + dragRect.Height;
 
                        Size snapSize = new Size(8, 8); 

                        int offsetX = (snapSize.Width / 2) * (left < 0 ? -1 : 1); 
                        int offsetY = (snapSize.Height / 2) * (top < 0 ? -1 : 1);

                        newRect.X = ((left + offsetX) / snapSize.Width) * snapSize.Width;
                        newRect.Y = ((top + offsetY) / snapSize.Height) * snapSize.Height; 

                        offsetX = (snapSize.Width / 2) * (right < 0 ? -1 : 1); 
                        offsetY = (snapSize.Height / 2) * (bottom < 0 ? -1 : 1); 

                        if (updateSize) { 
                            newRect.Width = ((right + offsetX) / snapSize.Width) * snapSize.Width - newRect.X;
                            newRect.Height = ((bottom + offsetY) / snapSize.Height) * snapSize.Height - newRect.Y;
                        }
 
                        updatedRect = newRect;
                    } 
                    else { 
                        updatedRect = dragRect;
                    } 

                    return updatedRect;
                }
 
                /// 
                ///  
                ///     Asks the handler to set the appropriate cursor 
                /// 
                public override void SetCursor() { 
                    compositionDesigner.compositionUI.OnSetCursor();
                }
            }
        } 
    }
} 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK