DynamicControl.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / DynamicData / DynamicData / DynamicControl.cs / 1305376 / DynamicControl.cs

                            namespace System.Web.DynamicData { 
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Web.Resources; 
    using System.Web.UI;
    using System.Collections.Generic; 
    using System.Reflection; 
    using System.Web.UI.WebControls;
    using System.Drawing; 
    using System.Diagnostics;

    /// 
    /// Control used to render Dynamic Data driven UI 
    /// 
    [ToolboxBitmap(typeof(DynamicControl), "DynamicControl.bmp")] 
    public class DynamicControl : Control, IAttributeAccessor, IFieldTemplateHost, IFieldFormattingOptions { 

        private bool _customConvertEmptyStringToNullSet; 
        private bool _customApplyFormatInEditModeSet;
        private MetaTable _table;
        private IMetaTable _iMetaTable;
        private IDictionary _attributes; 
        private IMetaColumn _iMetaColumn;
        private MetaColumn _column; 
 
        /// 
        ///  
        public DynamicControl() {
        }

        internal DynamicControl(IMetaTable table) { 
            _iMetaTable = table;
        } 
 
        internal DynamicControl(IMetaColumn column) {
            _iMetaColumn = column; 
        }

        /// The mode that the associated field template should be in (readonly, edit, insert)
        public DynamicControl(DataBoundControlMode mode) { 
            Mode = mode;
        } 
 
        /// 
        /// The name of the column that this control handles 
        /// 
        [
        Category("Data"),
        DefaultValue(""), 
        ResourceDescription("DynamicControlFieldCommon_DataField")
        ] 
        public string DataField { 
            get {
                object o = ViewState["DataField"]; 
                return ((o == null) ? String.Empty : (string)o);
            }
            set {
                if (!String.Equals(value, ViewState["DataField"])) { 
                    ViewState["DataField"] = value;
                } 
            } 
        }
 
        /// 
        /// The MetaColumn that this control is working with
        /// 
        [Browsable(false)] 
        public MetaColumn Column {
            get { 
                return _column; 
            }
            set { 
                _column = value;
                _iMetaColumn = value;
            }
        } 

        ///  
        /// The UIHint used by this control to locate the proper field template 
        /// 
        [ 
        Category("Behavior"),
        DefaultValue(""),
        ResourceDescription("DynamicControlFieldCommon_UIHint")
        ] 
        public virtual string UIHint {
            get { 
                object o = ViewState["UIHint"]; 
                return ((o == null) ? String.Empty : (string)o);
            } 
            set {
                ViewState["UIHint"] = value;
            }
        } 

        ///  
        /// Gets or sets the CSS class property of the DynamicControl 
        /// 
        [ 
        Category("Appearance"),
        DefaultValue(""),
        CssClassProperty()
        ] 
        public virtual string CssClass {
            get { 
                object o = ViewState["CssClass"]; 
                return ((o == null) ? String.Empty : (string)o);
            } 
            set {
                ViewState["CssClass"] = value;
            }
        } 

        ///  
        /// The MetaTable that this control is associated with 
        /// 
        [Browsable(false)] 
        public virtual MetaTable Table {
            get {
                if (_table == null) {
                    _table = this.FindMetaTable(); 

                    if (_table == null) { 
                        throw new Exception(String.Format(CultureInfo.CurrentCulture, 
                             DynamicDataResources.DynamicControl_ControlNeedsToExistInADataControlUsingDynamicDataSource));
                    } 
                }
                return _table;
            }
        } 

        private IMetaTable IMetaTable { 
            get { 
                return _iMetaTable ?? Table;
            } 
        }

        private IMetaColumn IMetaColumn {
            get { 
                return _iMetaColumn;
            } 
            set { 
                _iMetaColumn = value;
                _column = value as MetaColumn; 
            }
        }

        ///  
        /// The rendering mode: readonly, edit or insert
        ///  
        [ 
        DefaultValue(DataBoundControlMode.ReadOnly),
        Category("Behavior"), 
        ResourceDescription("DynamicField_Mode")
        ]
        public DataBoundControlMode Mode {
            get { 
                object o = ViewState["Mode"];
                return ((o == null) ? DataBoundControlMode.ReadOnly : (DataBoundControlMode)o); 
            } 
            set {
                ViewState["Mode"] = value; 
            }
        }

        ///  
        /// The validation group that the field template need to be in
        ///  
        [ 
        Category("Behavior"),
        DefaultValue(""), 
        Themeable(false),
        ResourceDescription("DynamicControlFieldCommon_ValidationGroup")
        ]
        public virtual string ValidationGroup { 
            get {
                object o = ViewState["ValidationGroup"]; 
                return ((o == null) ? String.Empty : (string)o); 
            }
            set { 
                ViewState["ValidationGroup"] = value;
            }
        }
 
        internal Control CreateControl() {
            Debug.Assert(FieldTemplate == null); 
 
            FieldTemplate = (Control)IMetaColumn.Model.FieldTemplateFactory.CreateFieldTemplate(Column, Mode, UIHint);
            if (FieldTemplate != null) { 
                ((IFieldTemplate)FieldTemplate).SetHost(this);

                // If we got some extra attributes declared on the tag, assign them to the user control if it has matching properties
                if (_attributes != null) { 
                    var ucType = FieldTemplate.GetType();
                    foreach (var entry in _attributes) { 
                        // Look for a public property by that name on th user control 
                        var propInfo = ucType.GetProperty(entry.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                        if (propInfo != null) { 
                            // Convert the value to the type of the property and set it
                            var value = PropertyConverter.ObjectFromString(propInfo.PropertyType, propInfo, entry.Value);
                            propInfo.SetValue(FieldTemplate, value, null);
                        } 
                    }
                } 
 
                // Give it the column name as its ID, unless there is already a control by that name
                string id = GetControlIDFromColumnName(IMetaColumn.Name); 
                if (FindControl(id) == null)
                    FieldTemplate.ID = id;
            }
            return FieldTemplate; 
        }
 
        ///  
        /// See base class documentation
        ///  
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected override void OnInit(EventArgs e) {
            base.OnInit(e);
 
            // Don't do anything in Design mode
            if (DesignMode) 
                return; 

            ResolveColumn(); 
            FieldTemplate = CreateControl();
            // Add it to the tree
            if (FieldTemplate != null) {
                Controls.Add(FieldTemplate); 
            }
        } 
 
        /// 
        /// Renders the underlying field template control. If this DynamicControl's CssClass tag is defined, 
        /// the underlying control's output will be wrapped in a span tag with that css class applied.
        /// 
        /// 
        protected override void Render(HtmlTextWriter writer) { 

            // In Design mode, simply render the string Databound.  Ideally, we'd do something fancier 
            // that takes into account the type of the column.  But at lesat, rendering *something* makes 
            // the design layout look reasonable
            if (DesignMode) { 
                writer.Write(DynamicDataResources.DynamicControlDesignRender);
                return;
            }
 
            // If there is a CSS class, output it in a span tag.  Otherwise, don't use any extra tag.
            if (!String.IsNullOrEmpty(CssClass)) { 
                writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass); 
                writer.RenderBeginTag(HtmlTextWriterTag.Span);
                base.Render(writer); 
                writer.RenderEndTag();
            }
            else {
                base.Render(writer); 
            }
        } 
 
        internal void ResolveColumn() {
            if (IMetaColumn == null) { 
                if (String.IsNullOrEmpty(DataField)) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.DynamicControl_ControlMustHaveDateFieldAttribute, GetType().Name, ID));
                } 

                IMetaColumn = IMetaTable.GetColumn(DataField); 
 

                // Try to get them various settings from the model, unless they were explicitely 
                // specified on the control
                if (String.IsNullOrEmpty(UIHint)) {
                    UIHint = IMetaColumn.UIHint;
                } 
                if (String.IsNullOrEmpty(DataFormatString)) {
                    DataFormatString = IMetaColumn.DataFormatString; 
                } 
                if (String.IsNullOrEmpty(NullDisplayText)) {
                    NullDisplayText = IMetaColumn.NullDisplayText; 
                }
                if (!_customConvertEmptyStringToNullSet) {
                    ConvertEmptyStringToNull = IMetaColumn.ConvertEmptyStringToNull;
                } 
                if (!_customApplyFormatInEditModeSet) {
                    ApplyFormatInEditMode = IMetaColumn.ApplyFormatInEditMode; 
                } 
                if (ViewState["HtmlEncode"] == null) {
                    HtmlEncode = IMetaColumn.HtmlEncode; 
                }
            }
        }
 
        /// 
        /// The Field Template that was created for this control 
        ///  
        [Browsable(false)]
        public Control FieldTemplate { get; private set; } 

        internal static string GetControlIDFromColumnName(string columnName) {
            return "__" + columnName;
        } 

        internal void SetAttributes(IDictionary attributes) { 
            _attributes = attributes; 
        }
 
        #region IAttributeAccessor Members

        /// 
        /// See IAttributeAccessor 
        /// 
        public string GetAttribute(string key) { 
            if (_attributes == null) 
                return String.Empty;
            return _attributes[key]; 
        }

        /// 
        /// See IAttributeAccessor 
        /// 
        public void SetAttribute(string key, string value) { 
            if (_attributes == null) { 
                _attributes = new Dictionary();
            } 
            _attributes[key] = value;
        }

        #endregion 

        #region IFieldTemplateHost Members 
 
        IFieldFormattingOptions IFieldTemplateHost.FormattingOptions {
            get { return this; } 
        }

        #endregion
 
        #region IFieldFormattingOptions Members
 
        ///  
        /// See IFieldFormattingOptions
        ///  
        [
        Category("Behavior"),
        DefaultValue(false),
        ResourceDescription("DynamicControlFieldCommon_ConvertEmptyStringToNull") 
        ]
        public bool ConvertEmptyStringToNull { 
            get { 
                object o = ViewState["ConvertEmptyStringToNull"];
                return (o == null ? false : (bool)o); 
            }
            set {
                _customConvertEmptyStringToNullSet = true;
                ViewState["ConvertEmptyStringToNull"] = value; 
            }
        } 
 
        /// 
        /// See IFieldFormattingOptions 
        /// 
        [
        Category("Behavior"),
        DefaultValue(false), 
        ResourceDescription("DynamicControlFieldCommon_ApplyFormatInEditMode")
        ] 
        public bool ApplyFormatInEditMode { 
            get {
                object o = ViewState["ApplyFormatInEditMode"]; 
                return (o == null ? false : (bool)o);
            }
            set {
                _customApplyFormatInEditModeSet = true; 
                ViewState["ApplyFormatInEditMode"] = value;
            } 
        } 

        ///  
        /// See IFieldFormattingOptions
        /// 
        [
        Category("Data"), 
        DefaultValue(""),
        ResourceDescription("DynamicControlFieldCommon_DataFormatString") 
        ] 
        public string DataFormatString {
            get { 
                object o = ViewState["DataFormatString"];
                return (o == null ? String.Empty : (string)o);
            }
            set { 
                ViewState["DataFormatString"] = value;
            } 
        } 

        ///  
        /// See IFieldFormattingOptions
        /// 
        [
        Category("Behavior"), 
        DefaultValue(true),
        ResourceDescription("DynamicControlFieldCommon_HtmlEncode") 
        ] 
        public bool HtmlEncode {
            get { 
                object o = ViewState["HtmlEncode"];
                return (o == null ? true : (bool)o);
            }
            set { 
                ViewState["HtmlEncode"] = value;
            } 
        } 

        ///  
        /// See IFieldFormattingOptions
        /// 
        [
        Category("Behavior"), 
        DefaultValue(""),
        ResourceDescription("DynamicControlFieldCommon_NullDisplayText") 
        ] 
        public string NullDisplayText {
            get { 
                object o = ViewState["NullDisplayText"];
                return (o == null ? String.Empty : (string)o);
            }
            set { 
                ViewState["NullDisplayText"] = value;
            } 
        } 

        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
namespace System.Web.DynamicData { 
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Web.Resources; 
    using System.Web.UI;
    using System.Collections.Generic; 
    using System.Reflection; 
    using System.Web.UI.WebControls;
    using System.Drawing; 
    using System.Diagnostics;

    /// 
    /// Control used to render Dynamic Data driven UI 
    /// 
    [ToolboxBitmap(typeof(DynamicControl), "DynamicControl.bmp")] 
    public class DynamicControl : Control, IAttributeAccessor, IFieldTemplateHost, IFieldFormattingOptions { 

        private bool _customConvertEmptyStringToNullSet; 
        private bool _customApplyFormatInEditModeSet;
        private MetaTable _table;
        private IMetaTable _iMetaTable;
        private IDictionary _attributes; 
        private IMetaColumn _iMetaColumn;
        private MetaColumn _column; 
 
        /// 
        ///  
        public DynamicControl() {
        }

        internal DynamicControl(IMetaTable table) { 
            _iMetaTable = table;
        } 
 
        internal DynamicControl(IMetaColumn column) {
            _iMetaColumn = column; 
        }

        /// The mode that the associated field template should be in (readonly, edit, insert)
        public DynamicControl(DataBoundControlMode mode) { 
            Mode = mode;
        } 
 
        /// 
        /// The name of the column that this control handles 
        /// 
        [
        Category("Data"),
        DefaultValue(""), 
        ResourceDescription("DynamicControlFieldCommon_DataField")
        ] 
        public string DataField { 
            get {
                object o = ViewState["DataField"]; 
                return ((o == null) ? String.Empty : (string)o);
            }
            set {
                if (!String.Equals(value, ViewState["DataField"])) { 
                    ViewState["DataField"] = value;
                } 
            } 
        }
 
        /// 
        /// The MetaColumn that this control is working with
        /// 
        [Browsable(false)] 
        public MetaColumn Column {
            get { 
                return _column; 
            }
            set { 
                _column = value;
                _iMetaColumn = value;
            }
        } 

        ///  
        /// The UIHint used by this control to locate the proper field template 
        /// 
        [ 
        Category("Behavior"),
        DefaultValue(""),
        ResourceDescription("DynamicControlFieldCommon_UIHint")
        ] 
        public virtual string UIHint {
            get { 
                object o = ViewState["UIHint"]; 
                return ((o == null) ? String.Empty : (string)o);
            } 
            set {
                ViewState["UIHint"] = value;
            }
        } 

        ///  
        /// Gets or sets the CSS class property of the DynamicControl 
        /// 
        [ 
        Category("Appearance"),
        DefaultValue(""),
        CssClassProperty()
        ] 
        public virtual string CssClass {
            get { 
                object o = ViewState["CssClass"]; 
                return ((o == null) ? String.Empty : (string)o);
            } 
            set {
                ViewState["CssClass"] = value;
            }
        } 

        ///  
        /// The MetaTable that this control is associated with 
        /// 
        [Browsable(false)] 
        public virtual MetaTable Table {
            get {
                if (_table == null) {
                    _table = this.FindMetaTable(); 

                    if (_table == null) { 
                        throw new Exception(String.Format(CultureInfo.CurrentCulture, 
                             DynamicDataResources.DynamicControl_ControlNeedsToExistInADataControlUsingDynamicDataSource));
                    } 
                }
                return _table;
            }
        } 

        private IMetaTable IMetaTable { 
            get { 
                return _iMetaTable ?? Table;
            } 
        }

        private IMetaColumn IMetaColumn {
            get { 
                return _iMetaColumn;
            } 
            set { 
                _iMetaColumn = value;
                _column = value as MetaColumn; 
            }
        }

        ///  
        /// The rendering mode: readonly, edit or insert
        ///  
        [ 
        DefaultValue(DataBoundControlMode.ReadOnly),
        Category("Behavior"), 
        ResourceDescription("DynamicField_Mode")
        ]
        public DataBoundControlMode Mode {
            get { 
                object o = ViewState["Mode"];
                return ((o == null) ? DataBoundControlMode.ReadOnly : (DataBoundControlMode)o); 
            } 
            set {
                ViewState["Mode"] = value; 
            }
        }

        ///  
        /// The validation group that the field template need to be in
        ///  
        [ 
        Category("Behavior"),
        DefaultValue(""), 
        Themeable(false),
        ResourceDescription("DynamicControlFieldCommon_ValidationGroup")
        ]
        public virtual string ValidationGroup { 
            get {
                object o = ViewState["ValidationGroup"]; 
                return ((o == null) ? String.Empty : (string)o); 
            }
            set { 
                ViewState["ValidationGroup"] = value;
            }
        }
 
        internal Control CreateControl() {
            Debug.Assert(FieldTemplate == null); 
 
            FieldTemplate = (Control)IMetaColumn.Model.FieldTemplateFactory.CreateFieldTemplate(Column, Mode, UIHint);
            if (FieldTemplate != null) { 
                ((IFieldTemplate)FieldTemplate).SetHost(this);

                // If we got some extra attributes declared on the tag, assign them to the user control if it has matching properties
                if (_attributes != null) { 
                    var ucType = FieldTemplate.GetType();
                    foreach (var entry in _attributes) { 
                        // Look for a public property by that name on th user control 
                        var propInfo = ucType.GetProperty(entry.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                        if (propInfo != null) { 
                            // Convert the value to the type of the property and set it
                            var value = PropertyConverter.ObjectFromString(propInfo.PropertyType, propInfo, entry.Value);
                            propInfo.SetValue(FieldTemplate, value, null);
                        } 
                    }
                } 
 
                // Give it the column name as its ID, unless there is already a control by that name
                string id = GetControlIDFromColumnName(IMetaColumn.Name); 
                if (FindControl(id) == null)
                    FieldTemplate.ID = id;
            }
            return FieldTemplate; 
        }
 
        ///  
        /// See base class documentation
        ///  
        [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
        protected override void OnInit(EventArgs e) {
            base.OnInit(e);
 
            // Don't do anything in Design mode
            if (DesignMode) 
                return; 

            ResolveColumn(); 
            FieldTemplate = CreateControl();
            // Add it to the tree
            if (FieldTemplate != null) {
                Controls.Add(FieldTemplate); 
            }
        } 
 
        /// 
        /// Renders the underlying field template control. If this DynamicControl's CssClass tag is defined, 
        /// the underlying control's output will be wrapped in a span tag with that css class applied.
        /// 
        /// 
        protected override void Render(HtmlTextWriter writer) { 

            // In Design mode, simply render the string Databound.  Ideally, we'd do something fancier 
            // that takes into account the type of the column.  But at lesat, rendering *something* makes 
            // the design layout look reasonable
            if (DesignMode) { 
                writer.Write(DynamicDataResources.DynamicControlDesignRender);
                return;
            }
 
            // If there is a CSS class, output it in a span tag.  Otherwise, don't use any extra tag.
            if (!String.IsNullOrEmpty(CssClass)) { 
                writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass); 
                writer.RenderBeginTag(HtmlTextWriterTag.Span);
                base.Render(writer); 
                writer.RenderEndTag();
            }
            else {
                base.Render(writer); 
            }
        } 
 
        internal void ResolveColumn() {
            if (IMetaColumn == null) { 
                if (String.IsNullOrEmpty(DataField)) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                        DynamicDataResources.DynamicControl_ControlMustHaveDateFieldAttribute, GetType().Name, ID));
                } 

                IMetaColumn = IMetaTable.GetColumn(DataField); 
 

                // Try to get them various settings from the model, unless they were explicitely 
                // specified on the control
                if (String.IsNullOrEmpty(UIHint)) {
                    UIHint = IMetaColumn.UIHint;
                } 
                if (String.IsNullOrEmpty(DataFormatString)) {
                    DataFormatString = IMetaColumn.DataFormatString; 
                } 
                if (String.IsNullOrEmpty(NullDisplayText)) {
                    NullDisplayText = IMetaColumn.NullDisplayText; 
                }
                if (!_customConvertEmptyStringToNullSet) {
                    ConvertEmptyStringToNull = IMetaColumn.ConvertEmptyStringToNull;
                } 
                if (!_customApplyFormatInEditModeSet) {
                    ApplyFormatInEditMode = IMetaColumn.ApplyFormatInEditMode; 
                } 
                if (ViewState["HtmlEncode"] == null) {
                    HtmlEncode = IMetaColumn.HtmlEncode; 
                }
            }
        }
 
        /// 
        /// The Field Template that was created for this control 
        ///  
        [Browsable(false)]
        public Control FieldTemplate { get; private set; } 

        internal static string GetControlIDFromColumnName(string columnName) {
            return "__" + columnName;
        } 

        internal void SetAttributes(IDictionary attributes) { 
            _attributes = attributes; 
        }
 
        #region IAttributeAccessor Members

        /// 
        /// See IAttributeAccessor 
        /// 
        public string GetAttribute(string key) { 
            if (_attributes == null) 
                return String.Empty;
            return _attributes[key]; 
        }

        /// 
        /// See IAttributeAccessor 
        /// 
        public void SetAttribute(string key, string value) { 
            if (_attributes == null) { 
                _attributes = new Dictionary();
            } 
            _attributes[key] = value;
        }

        #endregion 

        #region IFieldTemplateHost Members 
 
        IFieldFormattingOptions IFieldTemplateHost.FormattingOptions {
            get { return this; } 
        }

        #endregion
 
        #region IFieldFormattingOptions Members
 
        ///  
        /// See IFieldFormattingOptions
        ///  
        [
        Category("Behavior"),
        DefaultValue(false),
        ResourceDescription("DynamicControlFieldCommon_ConvertEmptyStringToNull") 
        ]
        public bool ConvertEmptyStringToNull { 
            get { 
                object o = ViewState["ConvertEmptyStringToNull"];
                return (o == null ? false : (bool)o); 
            }
            set {
                _customConvertEmptyStringToNullSet = true;
                ViewState["ConvertEmptyStringToNull"] = value; 
            }
        } 
 
        /// 
        /// See IFieldFormattingOptions 
        /// 
        [
        Category("Behavior"),
        DefaultValue(false), 
        ResourceDescription("DynamicControlFieldCommon_ApplyFormatInEditMode")
        ] 
        public bool ApplyFormatInEditMode { 
            get {
                object o = ViewState["ApplyFormatInEditMode"]; 
                return (o == null ? false : (bool)o);
            }
            set {
                _customApplyFormatInEditModeSet = true; 
                ViewState["ApplyFormatInEditMode"] = value;
            } 
        } 

        ///  
        /// See IFieldFormattingOptions
        /// 
        [
        Category("Data"), 
        DefaultValue(""),
        ResourceDescription("DynamicControlFieldCommon_DataFormatString") 
        ] 
        public string DataFormatString {
            get { 
                object o = ViewState["DataFormatString"];
                return (o == null ? String.Empty : (string)o);
            }
            set { 
                ViewState["DataFormatString"] = value;
            } 
        } 

        ///  
        /// See IFieldFormattingOptions
        /// 
        [
        Category("Behavior"), 
        DefaultValue(true),
        ResourceDescription("DynamicControlFieldCommon_HtmlEncode") 
        ] 
        public bool HtmlEncode {
            get { 
                object o = ViewState["HtmlEncode"];
                return (o == null ? true : (bool)o);
            }
            set { 
                ViewState["HtmlEncode"] = value;
            } 
        } 

        ///  
        /// See IFieldFormattingOptions
        /// 
        [
        Category("Behavior"), 
        DefaultValue(""),
        ResourceDescription("DynamicControlFieldCommon_NullDisplayText") 
        ] 
        public string NullDisplayText {
            get { 
                object o = ViewState["NullDisplayText"];
                return (o == null ? String.Empty : (string)o);
            }
            set { 
                ViewState["NullDisplayText"] = value;
            } 
        } 

        #endregion 
    }
}

// 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