From a6d77fa28828637990b2b2510b2c54613d10be1b Mon Sep 17 00:00:00 2001 From: Mike Rousos Date: Mon, 19 Nov 2018 11:58:24 -0500 Subject: [PATCH 1/7] WinForms DataGridView sample (#456) * Initial copy from https://code.msdn.microsoft.com/windowsdesktop/CSWinFormDataGridView-29783221 * Upgrade sln * Migrate csproj and remove a couple unused files * Work around dotnet/corefx#26745 * Replace description.html with README.md * Remove MSLPL license since this will now be covered by the MIT license in the repository root * Add screenshots to README * Remove license references in source comments since the sample now uses the repo's MIT license * Reformat old ReadMe.txt files into markdown and cleanup links * Small style improvements based on PR feedback --- windowsforms/README.md | 5 +- .../datagridview/CSWinFormDataGridView.sln | 22 ++ .../CSWinFormDataGridView.csproj | 70 ++++ .../MainForm.Designer.cs | 87 +++++ .../CustomDataGridViewColumn/MainForm.cs | 249 +++++++++++++ .../CustomDataGridViewColumn/MainForm.resx | 126 +++++++ .../MaskedTextBoxCell.cs | 235 ++++++++++++ .../MaskedTextBoxColumn.cs | 335 +++++++++++++++++ .../MaskedTextBoxEditingControl.cs | 271 ++++++++++++++ .../CustomDataGridViewColumn/README.md | 40 +++ .../DataGridViewPaging/MainForm.Designer.cs | 147 ++++++++ .../DataGridViewPaging/MainForm.cs | 146 ++++++++ .../DataGridViewPaging/MainForm.resx | 184 ++++++++++ .../DataGridViewPaging/README.md | 9 + .../MainForm.Designer.cs | 76 ++++ .../EditingControlHosting/MainForm.cs | 165 +++++++++ .../EditingControlHosting/MainForm.resx | 120 +++++++ .../EditingControlHosting/README.md | 56 +++ .../JustInTimeDataLoading/Cache.cs | 338 ++++++++++++++++++ .../MainForm.Designer.cs | 76 ++++ .../JustInTimeDataLoading/MainForm.cs | 83 +++++ .../JustInTimeDataLoading/MainForm.resx | 125 +++++++ .../JustInTimeDataLoading/README.md | 39 ++ .../MainForm.Designer.cs | 76 ++++ .../MultipleLayeredColumnHeader/MainForm.cs | 125 +++++++ .../MultipleLayeredColumnHeader/MainForm.resx | 120 +++++++ .../MultipleLayeredColumnHeader/README.md | 53 +++ .../CSWinFormDataGridView/Program.cs | 26 ++ .../Properties/AssemblyInfo.cs | 36 ++ .../Properties/Resources.Designer.cs | 71 ++++ .../Properties/Resources.resx | 117 ++++++ .../ResourceDeserializationExtensions.cs | 25 ++ windowsforms/datagridview/README.md | 26 ++ .../datagridview/images/screenshot1.png | Bin 0 -> 34337 bytes .../datagridview/images/screenshot2.png | Bin 0 -> 8214 bytes 35 files changed, 3677 insertions(+), 2 deletions(-) create mode 100644 windowsforms/datagridview/CSWinFormDataGridView.sln create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CSWinFormDataGridView.csproj create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.Designer.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.resx create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxCell.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxColumn.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxEditingControl.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/README.md create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.Designer.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.resx create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/README.md create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.Designer.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.resx create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/README.md create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/Cache.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.Designer.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.resx create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/README.md create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.Designer.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.resx create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/README.md create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/Program.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/Properties/AssemblyInfo.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.Designer.cs create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.resx create mode 100644 windowsforms/datagridview/CSWinFormDataGridView/ResourceDeserializationExtensions.cs create mode 100644 windowsforms/datagridview/README.md create mode 100644 windowsforms/datagridview/images/screenshot1.png create mode 100644 windowsforms/datagridview/images/screenshot2.png diff --git a/windowsforms/README.md b/windowsforms/README.md index 670b04fef23..0f62f88a954 100644 --- a/windowsforms/README.md +++ b/windowsforms/README.md @@ -14,6 +14,7 @@ If you're new to .NET Core, here are a few resources to help you understand the | ----------- | ----------- | | [Hello World - shared source](helloworld-sharedsource) | This sample shows you how to share source between a .NET Framework WinForms application and a .NET Core WinForms application. Use this to get the full .NET Framework tooling experience while still building for .NET Core. | | [Matching Game](matching-game) | This sample demonstrates simple event handling and timers in a .NET Core 3 WinForms application | +| [DataGridView Sample](datagridview) | This sample demonstrates DataGridView usage in .NET Core 3 | ## Getting Started @@ -50,7 +51,7 @@ Ideally you should migrate all projects in your solution to target .NET Core 3.0 1. Start from a working Solution. You must be able to open the solution in Visual Studio and double check that you can build and run without any issues. 2. If your solution also has server-side projects, such as ASP.NET, we recommend splitting your solution into different server and client solutions. For this effort, work with the client solution only. 3. Add a new .NET Core 3.0 Windows Forms project to the solution. Adding this project to a sibling folder to your existing 'head' project will make it easier to port references later (using relative paths to other projects or assemblies in the solution) -4. If your 'head' project uses NuGet packages, you must add the same NuGet packages to the new project. The new SDK-Style projects only support the PackageReference format for adding NuGet package references. If your existing project uses `packages.config`, you must migrate to the new format. You can use the Migrator Tool described [here](https://docs.microsoft.com/en-us/nuget/reference/migrate-packages-config-to-package-reference) to automate this process. +4. If your 'head' project uses NuGet packages, you must add the same NuGet packages to the new project. The new SDK-Style projects only support the PackageReference format for adding NuGet package references. If your existing project uses `packages.config`, you must migrate to the new format. You can use the Migrator Tool described [here](https://docs.microsoft.com/nuget/reference/migrate-packages-config-to-package-reference) to automate this process. 6. Copy the `PackageReference` elements generated in the previous step from the original project into the new project's .csproj file. 7. Copy the `ProjectReference` elements from the original project. Note: The new project format does not use the `Name` and `ProjectGuid` elements, so you can safely delete those. 8. At this point it's a good idea to try and restore/build to make sure all dependencies are properly configured. @@ -68,7 +69,7 @@ Most existing projects include an `AssemblyInfo.cs` file in the Properties folde false ``` #### Include the Windows.Compatibility Pack -Not every framework assembly is available in the .NET Core base class library. Windows applications like WinForms and WPF could have dependencies that are not available in .NET Core or .NET Standard. Adding a reference to the [Windows Compatibilty Pack](https://docs.microsoft.com/en-us/dotnet/core/porting/windows-compat-pack) will help reduce missing assembly dependencies as it includes several types that might be needed by your application. +Not every framework assembly is available in the .NET Core base class library. Windows applications like WinForms and WPF could have dependencies that are not available in .NET Core or .NET Standard. Adding a reference to the [Windows Compatibilty Pack](https://docs.microsoft.com/dotnet/core/porting/windows-compat-pack) will help reduce missing assembly dependencies as it includes several types that might be needed by your application. ```cmd dotnet add package Microsoft.Windows.Compatibility diff --git a/windowsforms/datagridview/CSWinFormDataGridView.sln b/windowsforms/datagridview/CSWinFormDataGridView.sln new file mode 100644 index 00000000000..fcdce55f535 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28218.60 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSWinFormDataGridView", "CSWinFormDataGridView\CSWinFormDataGridView.csproj", "{9FED9E6C-4128-4355-9487-74F1B7107CF2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9FED9E6C-4128-4355-9487-74F1B7107CF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FED9E6C-4128-4355-9487-74F1B7107CF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FED9E6C-4128-4355-9487-74F1B7107CF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FED9E6C-4128-4355-9487-74F1B7107CF2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CSWinFormDataGridView.csproj b/windowsforms/datagridview/CSWinFormDataGridView/CSWinFormDataGridView.csproj new file mode 100644 index 00000000000..274b8b50ee5 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CSWinFormDataGridView.csproj @@ -0,0 +1,70 @@ + + + + WinExe + netcoreapp3.0 + CSWinFormDataGridView + CSWinFormDataGridView + + + false + + + + + + + + + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + MainForm.cs + + + Resources.resx + + + + + + + + + + + + diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.Designer.cs b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.Designer.cs new file mode 100644 index 00000000000..ebea2533af8 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.Designer.cs @@ -0,0 +1,87 @@ +namespace CSWinFormDataGridView.CustomDataGridViewColumn +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.employeesDataGridView = new System.Windows.Forms.DataGridView(); + ((System.ComponentModel.ISupportInitialize)(this.employeesDataGridView)).BeginInit(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Verdana", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(23, 19); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(0, 16); + this.label1.TabIndex = 0; + // + // label2 + // + this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(23, 19); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(580, 87); + this.label2.TabIndex = 3; + this.label2.Text = resources.GetString("label2.Text"); + // + // employeesDataGridView + // + this.employeesDataGridView.Location = new System.Drawing.Point(26, 119); + this.employeesDataGridView.Name = "employeesDataGridView"; + this.employeesDataGridView.RowTemplate.Height = 21; + this.employeesDataGridView.Size = new System.Drawing.Size(577, 299); + this.employeesDataGridView.TabIndex = 2; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(634, 446); + this.Controls.Add(this.label2); + this.Controls.Add(this.employeesDataGridView); + this.Controls.Add(this.label1); + this.Name = "MainForm"; + this.Text = "DataGridViewCustomColumn Sample"; + this.Load += new System.EventHandler(this.MainForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.employeesDataGridView)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.DataGridView employeesDataGridView; + } +} \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.cs b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.cs new file mode 100644 index 00000000000..0c3f66328e3 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.cs @@ -0,0 +1,249 @@ +/************************************* Module Header **************************************\ +* Module Name: MaskedTextBoxColumn.cs +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* This sample demonstrates the use of custom column definitions within the Windows Forms +* DataGridView control. +* +* The Employee ID, SSN, State and Zip Code columns use MaskedTextBox controls for format +* and validate their input. +\******************************************************************************************/ + +#region Using directives +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +#endregion + + +namespace CSWinFormDataGridView.CustomDataGridViewColumn +{ + public partial class MainForm : Form + { + public MainForm() + { + InitializeComponent(); + } + + private void MainForm_Load(object sender, EventArgs e) + { + DataGridViewTextBoxColumn dgvTextBoxColumn; + MaskedTextBoxColumn mtbColumn; + + // + // Employee name. + // + dgvTextBoxColumn = new DataGridViewTextBoxColumn(); + dgvTextBoxColumn.HeaderText = "Name"; + dgvTextBoxColumn.Width = 120; + this.employeesDataGridView.Columns.Add(dgvTextBoxColumn); + + // + // Employee ID -- this will be of the format: + // [A-Z][0-9][0-9][0-9][0-9][0-9] + // + // this is well sutied to using a MaskedTextBox column. + // + mtbColumn = new MaskedTextBoxColumn(); + mtbColumn.HeaderText = "Employee ID"; + mtbColumn.Mask = "L00000"; + mtbColumn.Width = 75; + this.employeesDataGridView.Columns.Add(mtbColumn); + + // + // [American] Social Security number, of the format: + // ###-##-#### + // + mtbColumn = new MaskedTextBoxColumn(); + mtbColumn.HeaderText = "SSN"; + mtbColumn.Mask = "000-00-0000"; + mtbColumn.Width = 75; + this.employeesDataGridView.Columns.Add(mtbColumn); + + // + // Address + // + dgvTextBoxColumn = new DataGridViewTextBoxColumn(); + dgvTextBoxColumn.HeaderText = "Address"; + dgvTextBoxColumn.Width = 150; + this.employeesDataGridView.Columns.Add(dgvTextBoxColumn); + + // + // City + // + dgvTextBoxColumn = new DataGridViewTextBoxColumn(); + dgvTextBoxColumn.HeaderText = "City"; + dgvTextBoxColumn.Width = 75; + this.employeesDataGridView.Columns.Add(dgvTextBoxColumn); + + // + // State + // + mtbColumn = new MaskedTextBoxColumn(); + mtbColumn.HeaderText = "State"; + mtbColumn.Mask = "LL"; + mtbColumn.Width = 40; + this.employeesDataGridView.Columns.Add(mtbColumn); + + // + // Zip Code #####-#### (+4 optional) + // + mtbColumn = new MaskedTextBoxColumn(); + mtbColumn.HeaderText = "Zip Code"; + mtbColumn.Mask = "00000-0000"; + mtbColumn.Width = 75; + mtbColumn.ValidatingType = typeof(ZipCode); + this.employeesDataGridView.Columns.Add(mtbColumn); + + + // + // Department Code + // + dgvTextBoxColumn = new DataGridViewTextBoxColumn(); + dgvTextBoxColumn.HeaderText = "Department"; + dgvTextBoxColumn.ValueType = typeof(int); + dgvTextBoxColumn.Width = 75; + this.employeesDataGridView.Columns.Add(dgvTextBoxColumn); + } + } + + // Type that represents a US Zipcode to demonstrate + // the ValidatingType feature on the MaskedTextBox. + #region ZipCode Class + + public class ZipCode + { + private int zipCode; + private int plusFour; + + public ZipCode() + { + this.zipCode = 0; + this.plusFour = 0; + } + + public ZipCode(string in_zipCode) + { + parseFromString(in_zipCode, out zipCode, out plusFour); + } + + public ZipCode(int in_ivalue) + { + this.zipCode = in_ivalue; + this.plusFour = 0; + } + + + public static implicit operator ZipCode(string s) + { + return new ZipCode(s); + } + + public static implicit operator ZipCode(int i) + { + return new ZipCode(i); + } + + + protected static void parseFromString + ( + string in_string, + out int out_zipCode, + out int out_plusFour + ) + { + int zc = 0, pf = 0; + char[] charray; + int x = 0; + + if (in_string == null || in_string.Equals("")) + { + throw new ArgumentException("Invalid String"); + } + + charray = in_string.Trim().ToCharArray(); + + for (x = 0; x < 5; x++) + { + if (!Char.IsDigit(charray[x])) + { + throw new ArgumentException("Invalid String"); + } + + zc = zc * 10 + numfromchar(charray[x]); + } + + while (x < charray.Length && !Char.IsDigit(charray[x])) + { + x++; + } + + if (x < charray.Length) + { + for (int y = x; y < 4; y++) + { + if (!Char.IsDigit(charray[y])) + { + throw new ArgumentException("Invalid ZipCode String"); + } + + pf = pf * 10 + numfromchar(charray[y]); + } + } + + out_zipCode = zc; + out_plusFour = pf; + } + + + private static int numfromchar(char c) + { + switch (c) + { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + + default: + throw new ArgumentException("invalid digit"); + } + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(10); + + sb.Append(zipCode.ToString("00000")); + sb.Append("-"); + sb.Append(plusFour.ToString("0000")); + + return sb.ToString(); + } + } + + #endregion + +} \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.resx b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.resx new file mode 100644 index 00000000000..03c42f851a3 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MainForm.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + This sample demonstrates the use of custom column definitions within the Windows Forms DataGridView control. + +The Employee ID, SSN, State and Zip Code columns use MaskedTextBox controls for format and validate their input. + + + \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxCell.cs b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxCell.cs new file mode 100644 index 00000000000..5d850fdbe4f --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxCell.cs @@ -0,0 +1,235 @@ +/********************************* Module Header **********************************\ +* Module Name: MaskedTextBoxCell.cs +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* This sample demonstrates how to create a custom DataGridView column. +\**********************************************************************************/ + +#region Using directives +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +#endregion + + +namespace CSWinFormDataGridView.CustomDataGridViewColumn +{ + class MaskedTextBoxCell : DataGridViewTextBoxCell + { + private string mask; + private char promptChar; + private DataGridViewTriState includePrompt; + private DataGridViewTriState includeLiterals; + private Type validatingType; + + /// + /// Initializes a new instance of this class. Fortunately, there's + /// not much to do here except make sure that our base class is also + /// initialized properly. + /// + public MaskedTextBoxCell() + : base() + { + this.mask = ""; + this.promptChar = '_'; + this.includePrompt = DataGridViewTriState.NotSet; + this.includeLiterals = DataGridViewTriState.NotSet; + this.validatingType = typeof(string); + } + + /// + /// Whenever the user is to begin editing a cell of this type, the editing + /// control must be created, which in this column type's case is a subclass + /// of the MaskedTextBox control. + /// + /// This routine sets up all the properties and values on this control + /// before the editing begins. + /// + /// + /// + /// + public override void InitializeEditingControl(int rowIndex, + object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) + { + MaskedTextBoxEditingControl mtbEditingCtrl; + MaskedTextBoxColumn mtbColumn; + DataGridViewColumn dgvColumn; + + base.InitializeEditingControl(rowIndex, initialFormattedValue, + dataGridViewCellStyle); + + mtbEditingCtrl = DataGridView.EditingControl as MaskedTextBoxEditingControl; + + // + // Set up props that are specific to the MaskedTextBox + // + + dgvColumn = this.OwningColumn; // this.DataGridView.Columns[this.ColumnIndex]; + if (dgvColumn is MaskedTextBoxColumn) + { + mtbColumn = dgvColumn as MaskedTextBoxColumn; + + // + // get the mask from this instance or the parent column. + // + if (string.IsNullOrEmpty(this.mask)) + { + mtbEditingCtrl.Mask = mtbColumn.Mask; + } + else + { + mtbEditingCtrl.Mask = this.mask; + } + + // + // Prompt char. + // + mtbEditingCtrl.PromptChar = this.PromptChar; + + // + // IncludePrompt + // + if (this.includePrompt == DataGridViewTriState.NotSet) + { + //mtbEditingCtrl.IncludePrompt = mtbcol.IncludePrompt; + } + else + { + //mtbEditingCtrl.IncludePrompt = BoolFromTri(this.includePrompt); + } + + // + // IncludeLiterals + // + if (this.includeLiterals == DataGridViewTriState.NotSet) + { + //mtbEditingCtrl.IncludeLiterals = mtbcol.IncludeLiterals; + } + else + { + //mtbEditingCtrl.IncludeLiterals = BoolFromTri(this.includeLiterals); + } + + // + // Finally, the validating type ... + // + if (this.ValidatingType == null) + { + mtbEditingCtrl.ValidatingType = mtbColumn.ValidatingType; + } + else + { + mtbEditingCtrl.ValidatingType = this.ValidatingType; + } + + mtbEditingCtrl.Text = (string)this.Value; + } + } + + /// + /// Returns the type of the control that will be used for editing + /// cells of this type. This control must be a valid Windows Forms + /// control and must implement IDataGridViewEditingControl. + /// + public override Type EditType + { + get + { + return typeof(MaskedTextBoxEditingControl); + } + } + + /// + /// A string value containing the Mask against input for cells of + /// this type will be verified. + /// + public virtual string Mask + { + get + { + return this.mask; + } + set + { + this.mask = value; + } + } + + /// + /// The character to use for prompting for new input. + /// + public virtual char PromptChar + { + get + { + return this.promptChar; + } + set + { + this.promptChar = value; + } + } + + + /// + /// A boolean indicating whether to include prompt characters in + /// the Text property's value. + /// + public virtual DataGridViewTriState IncludePrompt + { + get + { + return this.includePrompt; + } + set + { + this.includePrompt = value; + } + } + + /// + /// A boolean value indicating whether to include literal characters + /// in the Text property's output value. + /// + public virtual DataGridViewTriState IncludeLiterals + { + get + { + return this.includeLiterals; + } + set + { + this.includeLiterals = value; + } + } + + /// + /// A Type object for the validating type. + /// + public virtual Type ValidatingType + { + get + { + return this.validatingType; + } + set + { + this.validatingType = value; + } + } + + /// + /// Quick routine to convert from DataGridViewTriState to boolean. + /// True goes to true while False and NotSet go to false. + /// + /// + /// + protected static bool BoolFromTri(DataGridViewTriState tri) + { + return (tri == DataGridViewTriState.True) ? true : false; + } + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxColumn.cs b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxColumn.cs new file mode 100644 index 00000000000..00cc92c9075 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxColumn.cs @@ -0,0 +1,335 @@ +/********************************* Module Header **********************************\ +* Module Name: MaskedTextBoxColumn.cs +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* This sample demonstrates how to create a custom DataGridView column. +\**********************************************************************************/ + +#region Using directives +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +#endregion + + +namespace CSWinFormDataGridView.CustomDataGridViewColumn +{ + /// + /// The base object for the custom column type. Programmers manipulate + /// the column types most often when working with the DataGridView, and + /// this one sets the basics and Cell Template values controlling the + /// default behaviour for cells of this column type. + /// + public class MaskedTextBoxColumn : DataGridViewColumn + { + private string mask; + private char promptChar; + private bool includePrompt; + private bool includeLiterals; + private Type validatingType; + + /// + /// Initializes a new instance of this class, making sure to pass + /// to its base constructor an instance of a MaskedTextBoxCell + /// class to use as the basic template. + /// + public MaskedTextBoxColumn() + : base(new MaskedTextBoxCell()) + { + } + + /// + /// Routine to convert from boolean to DataGridViewTriState. + /// + /// + /// + private static DataGridViewTriState TriBool(bool value) + { + return value ? DataGridViewTriState.True + : DataGridViewTriState.False; + } + + + /// + /// The template cell that will be used for this column by default, + /// unless a specific cell is set for a particular row. + /// + /// A MaskedTextBoxCell cell which will serve as the template cell + /// for this column. + /// + public override DataGridViewCell CellTemplate + { + get + { + return base.CellTemplate; + } + + set + { + // Only cell types that derive from MaskedTextBoxCell are supported + // as the cell template. + if (value != null && !value.GetType().IsAssignableFrom( + typeof(MaskedTextBoxCell))) + { + string s = "Cell type is not based upon the MaskedTextBoxCell."; + //CustomColumnMain.GetResourceManager().GetString("excNotMaskedTextBox"); + throw new InvalidCastException(s); + } + + base.CellTemplate = value; + } + } + + /// + /// Indicates the Mask property that is used on the MaskedTextBox + /// for entering new data into cells of this type. + /// + /// See the MaskedTextBox control documentation for more details. + /// + public virtual string Mask + { + get + { + return this.mask; + } + set + { + MaskedTextBoxCell mtbCell; + DataGridViewCell dgvCell; + int rowCount; + + if (this.mask != value) + { + this.mask = value; + + // + // First, update the value on the template cell. + // + mtbCell = (MaskedTextBoxCell)this.CellTemplate; + mtbCell.Mask = value; + + // + // Now set it on all cells in other rows as well. + // + if (this.DataGridView != null && this.DataGridView.Rows != null) + { + rowCount = this.DataGridView.Rows.Count; + for (int x = 0; x < rowCount; x++) + { + dgvCell = this.DataGridView.Rows.SharedRow(x).Cells[x]; + if (dgvCell is MaskedTextBoxCell) + { + mtbCell = (MaskedTextBoxCell)dgvCell; + mtbCell.Mask = value; + } + } + } + } + } + } + + + /// + /// By default, the MaskedTextBox uses the underscore (_) character + /// to prompt for required characters. This propertly lets you + /// choose a different one. + /// + /// See the MaskedTextBox control documentation for more details. + /// + public virtual char PromptChar + { + get + { + return this.promptChar; + } + set + { + MaskedTextBoxCell mtbCell; + DataGridViewCell dgvCell; + int rowCount; + + if (this.promptChar != value) + { + this.promptChar = value; + + // + // First, update the value on the template cell. + // + mtbCell = (MaskedTextBoxCell)this.CellTemplate; + mtbCell.PromptChar = value; + + // + // Now set it on all cells in other rows as well. + // + if (this.DataGridView != null && this.DataGridView.Rows != null) + { + rowCount = this.DataGridView.Rows.Count; + for (int x = 0; x < rowCount; x++) + { + dgvCell = this.DataGridView.Rows.SharedRow(x).Cells[x]; + if (dgvCell is MaskedTextBoxCell) + { + mtbCell = (MaskedTextBoxCell)dgvCell; + mtbCell.PromptChar = value; + } + } + } + } + } + } + + /// + /// Indicates whether any unfilled characters in the mask should be + /// be included as prompt characters when somebody asks for the text + /// of the MaskedTextBox for a particular cell programmatically. + /// + /// See the MaskedTextBox control documentation for more details. + /// + public virtual bool IncludePrompt + { + get + { + return this.includePrompt; + } + set + { + MaskedTextBoxCell mtbc; + DataGridViewCell dgvc; + int rowCount; + + if (this.includePrompt != value) + { + this.includePrompt = value; + + // + // First, update the value on the template cell. + // + mtbc = (MaskedTextBoxCell)this.CellTemplate; + mtbc.IncludePrompt = TriBool(value); + + // + // Now set it on all cells in other rows as well. + // + if (this.DataGridView != null && this.DataGridView.Rows != null) + { + rowCount = this.DataGridView.Rows.Count; + for (int x = 0; x < rowCount; x++) + { + dgvc = this.DataGridView.Rows.SharedRow(x).Cells[x]; + if (dgvc is MaskedTextBoxCell) + { + mtbc = (MaskedTextBoxCell)dgvc; + mtbc.IncludePrompt = TriBool(value); + } + } + } + } + } + } + + /// + /// Controls whether or not literal (non-prompt) characters should + /// be included in the output of the Text property for newly entered + /// data in a cell of this type. + /// + /// See the MaskedTextBox control documentation for more details. + /// + public virtual bool IncludeLiterals + { + get + { + return this.includeLiterals; + } + set + { + MaskedTextBoxCell mtbCell; + DataGridViewCell dgvCell; + int rowCount; + + if (this.includeLiterals != value) + { + this.includeLiterals = value; + + // + // First, update the value on the template cell. + // + mtbCell = (MaskedTextBoxCell)this.CellTemplate; + mtbCell.IncludeLiterals = TriBool(value); + + // + // Now set it on all cells in other rows as well. + // + if (this.DataGridView != null && this.DataGridView.Rows != null) + { + + rowCount = this.DataGridView.Rows.Count; + for (int x = 0; x < rowCount; x++) + { + dgvCell = this.DataGridView.Rows.SharedRow(x).Cells[x]; + if (dgvCell is MaskedTextBoxCell) + { + mtbCell = (MaskedTextBoxCell)dgvCell; + mtbCell.IncludeLiterals = TriBool(value); + } + } + } + } + } + } + + /// + /// Indicates the type against any data entered in the MaskedTextBox + /// should be validated. The MaskedTextBox control will attempt to + /// instantiate this type and assign the value from the contents of + /// the text box. An error will occur if it fails to assign to this + /// type. + /// + /// See the MaskedTextBox control documentation for more details. + /// + public virtual Type ValidatingType + { + get + { + return this.validatingType; + } + set + { + MaskedTextBoxCell mtbCell; + DataGridViewCell dgvCell; + int rowCount; + + if (this.validatingType != value) + { + this.validatingType = value; + + // + // First, update the value on the template cell. + // + mtbCell = (MaskedTextBoxCell)this.CellTemplate; + mtbCell.ValidatingType = value; + + // + // Now set it on all cells in other rows as well. + // + if (this.DataGridView != null && this.DataGridView.Rows != null) + { + rowCount = this.DataGridView.Rows.Count; + for (int x = 0; x < rowCount; x++) + { + dgvCell = this.DataGridView.Rows.SharedRow(x).Cells[x]; + if (dgvCell is MaskedTextBoxCell) + { + mtbCell = (MaskedTextBoxCell)dgvCell; + mtbCell.ValidatingType = value; + } + } + } + } + } + } + + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxEditingControl.cs b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxEditingControl.cs new file mode 100644 index 00000000000..c903ada129f --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/MaskedTextBoxEditingControl.cs @@ -0,0 +1,271 @@ +/********************************* Module Header **********************************\ +* Module Name: MaskedTextBoxEditingControl.cs +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* This sample demonstrates how to create a custom DataGridView column. +\**********************************************************************************/ + +#region Using directives +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +#endregion + + +namespace CSWinFormDataGridView.CustomDataGridViewColumn +{ + public class MaskedTextBoxEditingControl : MaskedTextBox, IDataGridViewEditingControl + { + protected int rowIndex; + protected DataGridView dataGridView; + protected bool valueChanged = false; + + public MaskedTextBoxEditingControl() + { + + } + + protected override void OnTextChanged(EventArgs e) + { + base.OnTextChanged(e); + + // Let the DataGridView know about the value change + NotifyDataGridViewOfValueChange(); + } + + /// + /// Notify DataGridView that the value has changed. + /// + protected virtual void NotifyDataGridViewOfValueChange() + { + this.valueChanged = true; + if (this.dataGridView != null) + { + this.dataGridView.NotifyCurrentCellDirty(true); + } + } + + + #region IDataGridViewEditingControl Members + + // Indicates the cursor that should be shown when the user hovers their + // mouse over this cell when the editing control is shown. + public Cursor EditingPanelCursor + { + get + { + return Cursors.IBeam; + } + } + + + // Returns or sets the parent DataGridView. + public DataGridView EditingControlDataGridView + { + get + { + return this.dataGridView; + } + + set + { + this.dataGridView = value; + } + } + + + // Sets/Gets the formatted value contents of this cell. + public object EditingControlFormattedValue + { + set + { + this.Text = value.ToString(); + NotifyDataGridViewOfValueChange(); + } + get + { + return this.Text; + } + + } + + // Get the value of the editing control for formatting. + public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) + { + return this.Text; + } + + // Process input key and determine if the key should be used for the editing control + // or allowed to be processed by the grid. Handle cursor movement keys for the MaskedTextBox + // control; otherwise if the DataGridView doesn't want the input key then let the editing control handle it. + public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) + { + switch (keyData & Keys.KeyCode) + { + case Keys.Right: + // + // If the end of the selection is at the end of the string + // let the DataGridView treat the key message + // + if (!(this.SelectionLength == 0 + && this.SelectionStart == this.ToString().Length)) + { + return true; + } + break; + + case Keys.Left: + // + // If the end of the selection is at the begining of the + // string or if the entire text is selected send this character + // to the dataGridView; else process the key event. + // + if (!(this.SelectionLength == 0 + && this.SelectionStart == 0)) + { + return true; + } + break; + + case Keys.Home: + case Keys.End: + if (this.SelectionLength != this.ToString().Length) + { + return true; + } + break; + + case Keys.Prior: + case Keys.Next: + if (this.valueChanged) + { + return true; + } + break; + + case Keys.Delete: + if (this.SelectionLength > 0 || this.SelectionStart < this.ToString().Length) + { + return true; + } + break; + } + + // + // defer to the DataGridView and see if it wants it. + // + return !dataGridViewWantsInputKey; + } + + + // Prepare the editing control for edit. + public void PrepareEditingControlForEdit(bool selectAll) + { + if (selectAll) + { + SelectAll(); + } + else + { + // + // Do not select all the text, but position the caret at the + // end of the text. + // + this.SelectionStart = this.ToString().Length; + } + } + + // Indicates whether or not the parent DataGridView control should + // reposition the editing control every time value change is indicated. + // There is no need to do this for the MaskedTextBox. + public bool RepositionEditingControlOnValueChange + { + get + { + return false; + } + } + + + // Indicates the row index of this cell. This is often -1 for the + // template cell, but for other cells, might actually have a value + // greater than or equal to zero. + public int EditingControlRowIndex + { + get + { + return this.rowIndex; + } + + set + { + this.rowIndex = value; + } + } + + + + // Make the MaskedTextBox control match the style and colors of + // the host DataGridView control and other editing controls + // before showing the editing control. + public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) + { + this.Font = dataGridViewCellStyle.Font; + this.ForeColor = dataGridViewCellStyle.ForeColor; + this.BackColor = dataGridViewCellStyle.BackColor; + this.TextAlign = translateAlignment(dataGridViewCellStyle.Alignment); + } + + + // Gets or sets our flag indicating whether the value has changed. + public bool EditingControlValueChanged + { + get + { + return valueChanged; + } + + set + { + this.valueChanged = value; + } + } + + #endregion // IDataGridViewEditingControl. + + + /// + /// Routine to translate between DataGridView content alignments and text + /// box horizontal alignments. + /// + /// + /// + private static HorizontalAlignment translateAlignment(DataGridViewContentAlignment align) + { + switch (align) + { + case DataGridViewContentAlignment.TopLeft: + case DataGridViewContentAlignment.MiddleLeft: + case DataGridViewContentAlignment.BottomLeft: + return HorizontalAlignment.Left; + + case DataGridViewContentAlignment.TopCenter: + case DataGridViewContentAlignment.MiddleCenter: + case DataGridViewContentAlignment.BottomCenter: + return HorizontalAlignment.Center; + + case DataGridViewContentAlignment.TopRight: + case DataGridViewContentAlignment.MiddleRight: + case DataGridViewContentAlignment.BottomRight: + return HorizontalAlignment.Right; + } + + throw new ArgumentException("Error: Invalid Content Alignment!"); + } + + + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/README.md b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/README.md new file mode 100644 index 00000000000..369ad25a8be --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/CustomDataGridViewColumn/README.md @@ -0,0 +1,40 @@ +# CustomDataGridViewColumn Sample + +This sample demonstrates how to create a custom DataGridView column. + +## Remarks + +There are six standard DataGridViewColumn types for use as follows: + +- DataGridViewTextBoxColumn +- DataGridViewCheckedBoxColumn +- DataGridViewComboBoxColumn +- DataGridViewLinkColumn +- DataGridViewButtonColumn +- DataGridViewImageColumn + +However, developers may want to use a different control for editing on the column, +e.g. MarkedTextBox, DateTimePicker etc. This feature can be achieved in two ways: + +1. Create a custom DataGridViewColumn; + + The code in this CustomDataGridViewColumn sample demonstrates how to do this. + +2. Place the editing control on the current cell when editing begins, and hide + the editing control when the editing completes. For the details of this + approach, please refer to the EditingControlHosting sample. + + +## Creation + +1. Create a MaskedTextBoxEditingControl class derive from MaskedTextBox class + and IDataGridViewEditingControl class, see the code in the + MaskedTextBoxEditingControl.cs file for the implementation details. + +2. Create a MaskedTextBoxCell class derive from DataGridViewTextBoxCell class, + see the code in the MaskedTextBoxCell.cs file for the implementation details. + +3. Create a MaskedTextBoxColumn class derive from DataGridViewColumn class, + see the code in the MaskedTextBoxColumn.cs file for the implementation details. + +4. Build the program. diff --git a/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.Designer.cs b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.Designer.cs new file mode 100644 index 00000000000..9e3c8710bae --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.Designer.cs @@ -0,0 +1,147 @@ +namespace CSWinFormDataGridView.DataGridViewPaging +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.dataGridView1 = new System.Windows.Forms.DataGridView(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.toolStripButtonFirst = new System.Windows.Forms.ToolStripButton(); + this.toolStripButtonPrev = new System.Windows.Forms.ToolStripButton(); + this.toolStripButtonNext = new System.Windows.Forms.ToolStripButton(); + this.toolStripButtonLast = new System.Windows.Forms.ToolStripButton(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); + this.groupBox1.SuspendLayout(); + this.toolStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // dataGridView1 + // + this.dataGridView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dataGridView1.Location = new System.Drawing.Point(3, 44); + this.dataGridView1.Name = "dataGridView1"; + this.dataGridView1.Size = new System.Drawing.Size(632, 425); + this.dataGridView1.TabIndex = 0; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.toolStrip1); + this.groupBox1.Controls.Add(this.dataGridView1); + this.groupBox1.Location = new System.Drawing.Point(12, 23); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(638, 472); + this.groupBox1.TabIndex = 1; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "groupBox1"; + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripButtonFirst, + this.toolStripButtonPrev, + this.toolStripButtonNext, + this.toolStripButtonLast}); + this.toolStrip1.Location = new System.Drawing.Point(3, 16); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(632, 25); + this.toolStrip1.TabIndex = 1; + this.toolStrip1.Text = "toolStrip1"; + // + // toolStripButtonFirst + // + this.toolStripButtonFirst.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.toolStripButtonFirst.Image = resources.GetImage("toolStripButtonFirst.Image"); + this.toolStripButtonFirst.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonFirst.Name = "toolStripButtonFirst"; + this.toolStripButtonFirst.Size = new System.Drawing.Size(59, 22); + this.toolStripButtonFirst.Text = "First Page"; + this.toolStripButtonFirst.Click += new System.EventHandler(this.toolStripButtonFirst_Click); + // + // toolStripButtonPrev + // + this.toolStripButtonPrev.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.toolStripButtonPrev.Image = resources.GetImage("toolStripButtonPrev.Image"); + this.toolStripButtonPrev.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonPrev.Name = "toolStripButtonPrev"; + this.toolStripButtonPrev.Size = new System.Drawing.Size(79, 22); + this.toolStripButtonPrev.Text = "Previous Page"; + this.toolStripButtonPrev.Click += new System.EventHandler(this.toolStripButtonPrev_Click); + // + // toolStripButtonNext + // + this.toolStripButtonNext.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.toolStripButtonNext.Image = resources.GetImage("toolStripButtonNext.Image"); + this.toolStripButtonNext.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonNext.Name = "toolStripButtonNext"; + this.toolStripButtonNext.Size = new System.Drawing.Size(61, 22); + this.toolStripButtonNext.Text = "Next Page"; + this.toolStripButtonNext.Click += new System.EventHandler(this.toolStripButtonNext_Click); + // + // toolStripButtonLast + // + this.toolStripButtonLast.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.toolStripButtonLast.Image = resources.GetImage("toolStripButtonLast.Image"); + this.toolStripButtonLast.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonLast.Name = "toolStripButtonLast"; + this.toolStripButtonLast.Size = new System.Drawing.Size(58, 22); + this.toolStripButtonLast.Text = "Last Page"; + this.toolStripButtonLast.Click += new System.EventHandler(this.toolStripButtonLast_Click); + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(662, 507); + this.Controls.Add(this.groupBox1); + this.Name = "MainForm"; + this.Text = "MainForm"; + this.Load += new System.EventHandler(this.MainForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.DataGridView dataGridView1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.ToolStripButton toolStripButtonFirst; + private System.Windows.Forms.ToolStripButton toolStripButtonPrev; + private System.Windows.Forms.ToolStripButton toolStripButtonNext; + private System.Windows.Forms.ToolStripButton toolStripButtonLast; + } +} \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.cs b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.cs new file mode 100644 index 00000000000..78ddb7ba0b3 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.cs @@ -0,0 +1,146 @@ +/********************************* Module Header **********************************\ +* Module Name: DataGridViewPaging +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* This sample demonstrates how to page data in the DataGridView control; +\**********************************************************************************/ + +#region Using directives +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Data.SqlClient; +#endregion + + +namespace CSWinFormDataGridView.DataGridViewPaging +{ + public partial class MainForm : Form + { + public MainForm() + { + InitializeComponent(); + } + + private int PageSize = 30; // 30 rows per page + private int CurrentPageIndex = 1; + private int TotalPage; + + private string connstr = + "Persist Security Info=False;" + + "Integrated Security=SSPI;" + + "Initial Catalog=Northwind;" + + "server=localhost"; + + private SqlConnection conn; + private SqlDataAdapter adapter; + private SqlCommand command; + + private void MainForm_Load(object sender, EventArgs e) + { + this.conn = new SqlConnection(connstr); + this.adapter = new SqlDataAdapter(); + this.command = conn.CreateCommand(); + + // Get total count of the pages; + this.GetTotalPageCount(); + + this.dataGridView1.ReadOnly = true; + + // Load the first page of data; + this.dataGridView1.DataSource = GetPageData(1); + } + + private void GetTotalPageCount() + { + command.CommandText = "Select Count(OrderID) From Orders"; + + try + { + conn.Open(); + int rowCount = (int)command.ExecuteScalar(); + + this.TotalPage = rowCount / PageSize; + + if (rowCount % PageSize > 0) + { + this.TotalPage += 1; + } + } + finally + { + conn.Close(); + } + } + + private DataTable GetPageData(int page) + { + DataTable dt = new DataTable(); + + if (page == 1) + { + command.CommandText = + "Select Top " + PageSize + " * From Orders Order By OrderID"; + } + else + { + int lowerPageBoundary = ( page - 1) * PageSize; + + command.CommandText = "Select Top " + PageSize + + " * From Orders " + + " WHERE OrderID NOT IN "+ + " (SELECT TOP " + lowerPageBoundary + " OrderID From Orders Order By OrderID) "+ + " Order By OrderID"; + } + try + { + this.conn.Open(); + this.adapter.SelectCommand = command; + this.adapter.Fill(dt); + } + finally + { + conn.Close(); + } + + return dt; + } + + private void toolStripButtonFirst_Click(object sender, EventArgs e) + { + this.CurrentPageIndex = 1; + this.dataGridView1.DataSource = GetPageData(this.CurrentPageIndex); + } + + private void toolStripButtonPrev_Click(object sender, EventArgs e) + { + if (this.CurrentPageIndex > 1) + { + this.CurrentPageIndex--; + this.dataGridView1.DataSource = GetPageData(this.CurrentPageIndex); + } + } + + private void toolStripButtonNext_Click(object sender, EventArgs e) + { + if (this.CurrentPageIndex < this.TotalPage) + { + this.CurrentPageIndex++; + this.dataGridView1.DataSource = GetPageData(this.CurrentPageIndex); + } + } + + private void toolStripButtonLast_Click(object sender, EventArgs e) + { + this.CurrentPageIndex = TotalPage; + this.dataGridView1.DataSource = GetPageData(this.CurrentPageIndex); + } + + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.resx b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.resx new file mode 100644 index 00000000000..e231f454902 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/MainForm.resx @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + 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 + + + \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/README.md b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/README.md new file mode 100644 index 00000000000..f418d34ff96 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/DataGridViewPaging/README.md @@ -0,0 +1,9 @@ +## DataGridViewPaging Sample + +This sample demonstrates how to page data in the DataGridView control; + +## Code Logic + +1. Get total count of the rows in the table. +2. Calculate total count of pages. +3. Load each page on demand. diff --git a/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.Designer.cs b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.Designer.cs new file mode 100644 index 00000000000..14597efe69f --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.Designer.cs @@ -0,0 +1,76 @@ +namespace CSWinFormDataGridView.EditingControlHosting +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.dataGridView1 = new System.Windows.Forms.DataGridView(); + this.label1 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); + this.SuspendLayout(); + // + // dataGridView1 + // + this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dataGridView1.Location = new System.Drawing.Point(22, 57); + this.dataGridView1.Name = "dataGridView1"; + this.dataGridView1.Size = new System.Drawing.Size(586, 350); + this.dataGridView1.TabIndex = 0; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Verdana", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(19, 20); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(589, 14); + this.label1.TabIndex = 1; + this.label1.Text = "This sample demonstrates how to host a control in the current DataGridViewCell f" + + "or editing."; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(628, 441); + this.Controls.Add(this.label1); + this.Controls.Add(this.dataGridView1); + this.Name = "MainForm"; + this.Text = "Host Control In DataGridViewCell For Editing"; + this.Load += new System.EventHandler(this.MainForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.DataGridView dataGridView1; + private System.Windows.Forms.Label label1; + } +} \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.cs b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.cs new file mode 100644 index 00000000000..45b0947b84c --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.cs @@ -0,0 +1,165 @@ +/************************************* Module Header **************************************\ +* Module Name: EditingControlHosting +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* This sample demonstrates how to host a control in the current DataGridViewCell for +* editing. +\******************************************************************************************/ + +#region Using directives +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +#endregion + + +namespace CSWinFormDataGridView.EditingControlHosting +{ + public partial class MainForm : Form + { + public MainForm() + { + InitializeComponent(); + } + + private MaskedTextBox maskedTextBoxForEditing; + private bool IsKeyPressHandled = false; + + private void MainForm_Load(object sender, EventArgs e) + { + this.maskedTextBoxForEditing = new MaskedTextBox(); + + // The "000-00-0000" mask allows only digits can be input + this.maskedTextBoxForEditing.Mask = "000-00-0000"; + // this.maskedTextBoxForEditing.TextMaskFormat = MaskFormat.ExcludePromptAndLiterals; + + // Hide the MaskedTextBox + this.maskedTextBoxForEditing.Visible = false; + + // Add the MaskedTextBox to the DataGridView's control collection + this.dataGridView1.Controls.Add(this.maskedTextBoxForEditing); + + // Add a DataGridViewTextBoxColumn to the + DataGridViewTextBoxColumn tc = new DataGridViewTextBoxColumn(); + tc.HeaderText = "Mask Column"; + tc.Name = "MaskColumn"; + this.dataGridView1.Columns.Add(tc); + + // Add some empty rows for testing purpose. + for (int j = 0; j < 30; j++) + { + this.dataGridView1.Rows.Add(); + } + + // Handle the CellBeginEdit event to show the MaskedTextBox on + // the current editing cell + this.dataGridView1.CellBeginEdit += + new DataGridViewCellCancelEventHandler(dataGridView1_CellBeginEdit); + + // Handle the CellEndEdit event to hide the MaskedTextBox when + // editing completes. + this.dataGridView1.CellEndEdit += new DataGridViewCellEventHandler(dataGridView1_CellEndEdit); + + // Handle the Scroll event to adjust the location of the MaskedTextBox as it is showing + // when scrolling the DataGridView + this.dataGridView1.Scroll += new ScrollEventHandler(dataGridView1_Scroll); + + // Handle the EditingControlShowing event to pass the focus to the + // MaskedTextBox when begin editing with keystrokes + this.dataGridView1.EditingControlShowing += + new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing); + } + + void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) + { + // If the current cell is on the "MaskColumn", we use the MaskedTextBox control + // for editing instead of the default TextBox control; + if (e.ColumnIndex == this.dataGridView1.Columns["MaskColumn"].Index) + { + // Calculate the cell bounds of the current cell + Rectangle rect = this.dataGridView1.GetCellDisplayRectangle( + e.ColumnIndex, e.RowIndex, true); + // Adjust the MaskedTextBox's size and location to fit the cell + this.maskedTextBoxForEditing.Size = rect.Size; + this.maskedTextBoxForEditing.Location = rect.Location; + + // Set value for the MaskedTextBox + if (this.dataGridView1.CurrentCell.Value != null) + { + this.maskedTextBoxForEditing.Text = this.dataGridView1.CurrentCell.Value.ToString(); + } + + // Show the MaskedTextBox + this.maskedTextBoxForEditing.Visible = true; + } + } + + void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + // When finish editing on the "MaskColumn", we replace the cell value with + // the text typed in the MaskedTextBox, and hide the MaskedTextBox; + if (e.ColumnIndex == this.dataGridView1.Columns["MaskColumn"].Index) + { + this.dataGridView1.CurrentCell.Value = this.maskedTextBoxForEditing.Text; + this.maskedTextBoxForEditing.Text = ""; + this.maskedTextBoxForEditing.Visible = false; + } + } + + void dataGridView1_Scroll(object sender, ScrollEventArgs e) + { + if (this.dataGridView1.IsCurrentCellInEditMode == true) + { + // Adjust the location for the MaskedTextBox while scrolling + Rectangle rect = this.dataGridView1.GetCellDisplayRectangle( + this.dataGridView1.CurrentCell.ColumnIndex, + this.dataGridView1.CurrentCell.RowIndex, true); + + Console.WriteLine(rect.ToString()); + Console.WriteLine(this.dataGridView1.CurrentCellAddress.ToString()); + Console.WriteLine(""); + + if (rect.X <= 0 || rect.Y <= 0) + { + this.maskedTextBoxForEditing.Visible = false; + } + else + { + this.maskedTextBoxForEditing.Location = rect.Location; + } + } + } + + void dataGridView1_EditingControlShowing(object sender, + DataGridViewEditingControlShowingEventArgs e) + { + if (!this.IsKeyPressHandled + && this.dataGridView1.CurrentCell.ColumnIndex == + this.dataGridView1.Columns["MaskColumn"].Index) + { + TextBox tb = e.Control as TextBox; + tb.KeyPress += new KeyPressEventHandler(tb_KeyPress); + this.IsKeyPressHandled = true; + } + } + + void tb_KeyPress(object sender, KeyPressEventArgs e) + { + if (this.dataGridView1.CurrentCell.ColumnIndex == + this.dataGridView1.Columns["MaskColumn"].Index) + { + // Prevent the key char to be input in the editing control + e.Handled = true; + + // Set focus to the MaskedTextBox for editing. + this.maskedTextBoxForEditing.Focus(); + } + } + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.resx b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.resx new file mode 100644 index 00000000000..19dc0dd8b39 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/MainForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/README.md b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/README.md new file mode 100644 index 00000000000..14d21344ba1 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/EditingControlHosting/README.md @@ -0,0 +1,56 @@ +# EditingControlHosting Sample + +This sample demonstrates how to host a control in the current DataGridViewCell +for editing. + +## Remarks + +There are six standard DataGridViewColumn types for use as follows: + +DataGridViewTextBoxColumn +DataGridViewCheckedBoxColumn +DataGridViewComboBoxColumn +DataGridViewLinkColumn +DataGridViewButtonColumn +DataGridViewImageColumn + +However, developers may want to use a different control for editing on the column, +e.g. MarkedTextBox, DateTimePicker etc. This feature can be achieved in two ways: + +1. Create a custom DataGridViewColumn; + + For the details of how to do this, please refer to the CustomDataGridViewColumn + sample. + +2. Place the editing control on the current cell when editing begins, and hide + the editing control when the editing completes. + + This sample demonstrates how to do this. + + +## Code Logic + +1. Create an instance of the editing control, in this sample the editing control + is MaskedTextBox. + +2. Specify a mask for the MaskedTextBox and add the MaskedTextBox to the + control collection of the DataGridView. + +3. Hide the MaskedTextBox. + +4. Handle the CellBeginEdit event to show the MaskedTextBox on the current + editing cell. + +5. Handle the CellEndEdit event to hide the MaskedTextBox when editing completes. + +6. Handle the Scroll event to adjust the location of the MaskedTextBox as it is + showing when scrolling the DataGridView. + +7. Handle the EditingControlShowing event to pass the focus to the MaskedTextBox + when begin editing with keystrokes. + + +## References + +- [DataGridView Class](https://docs.microsoft.com/dotnet/api/system.windows.forms.datagridview) + diff --git a/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/Cache.cs b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/Cache.cs new file mode 100644 index 00000000000..fa3988ed7d1 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/Cache.cs @@ -0,0 +1,338 @@ +/************************************* Module Header **************************************\ +* Module Name: JustInTimeDataLoading.Cache +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* +* This sample demonstrates how to use virtual mode in the DataGridView control +* with a data cache that loads data from a server only when it is needed. +* This kind of data loading is called "Just-in-time data loading". +\******************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; +using System.Data.SqlClient; + +namespace CSWinFormDataGridView.JustInTimeDataLoading +{ + + #region Cache Class + + public class Cache + { + private static int RowsPerPage; + + /// + /// Represents one page of data. + /// + public struct DataPage + { + public DataTable table; + private int lowestIndexValue; + private int highestIndexValue; + + public DataPage(DataTable table, int rowIndex) + { + this.table = table; + lowestIndexValue = MapToLowerBoundary(rowIndex); + highestIndexValue = MapToUpperBoundary(rowIndex); + System.Diagnostics.Debug.Assert(lowestIndexValue >= 0); + System.Diagnostics.Debug.Assert(highestIndexValue >= 0); + } + + public int LowestIndex + { + get + { + return lowestIndexValue; + } + } + + public int HighestIndex + { + get + { + return highestIndexValue; + } + } + + public static int MapToLowerBoundary(int rowIndex) + { + // Return the lowest index of a page containing the given index. + return (rowIndex / RowsPerPage) * RowsPerPage; + } + + private static int MapToUpperBoundary(int rowIndex) + { + // Return the highest index of a page containing the given index. + return MapToLowerBoundary(rowIndex) + RowsPerPage - 1; + } + } + + private DataPage[] cachePages; + private IDataPageRetriever dataSupply; + + public Cache(IDataPageRetriever dataSupplier, int rowsPerPage) + { + dataSupply = dataSupplier; + Cache.RowsPerPage = rowsPerPage; + LoadFirstTwoPages(); + } + + /// + /// Sets the value of the element parameter if the value is in the cache. + /// + /// + /// + /// + /// + private bool IfPageCached_ThenSetElement(int rowIndex, + int columnIndex, ref string element) + { + if (IsRowCachedInPage(0, rowIndex)) + { + element = cachePages[0].table + .Rows[rowIndex % RowsPerPage][columnIndex].ToString(); + return true; + } + else if (IsRowCachedInPage(1, rowIndex)) + { + element = cachePages[1].table + .Rows[rowIndex % RowsPerPage][columnIndex].ToString(); + return true; + } + + return false; + } + + public string RetrieveElement(int rowIndex, int columnIndex) + { + string element = null; + + if (IfPageCached_ThenSetElement(rowIndex, columnIndex, ref element)) + { + return element; + } + else + { + return RetrieveData_CacheIt_ThenReturnElement( + rowIndex, columnIndex); + } + } + + private void LoadFirstTwoPages() + { + cachePages = new DataPage[]{ + new DataPage(dataSupply.SupplyPageOfData( + DataPage.MapToLowerBoundary(0), RowsPerPage), 0), + new DataPage(dataSupply.SupplyPageOfData( + DataPage.MapToLowerBoundary(RowsPerPage), + RowsPerPage), RowsPerPage)}; + } + + private string RetrieveData_CacheIt_ThenReturnElement( + int rowIndex, int columnIndex) + { + // Retrieve a page worth of data containing the requested value. + DataTable table = dataSupply.SupplyPageOfData( + DataPage.MapToLowerBoundary(rowIndex), RowsPerPage); + + // Replace the cached page furthest from the requested cell + // with a new page containing the newly retrieved data. + cachePages[GetIndexToUnusedPage(rowIndex)] = new DataPage(table, rowIndex); + + return RetrieveElement(rowIndex, columnIndex); + } + + /// + /// Returns the index of the cached page most distant from the given index + /// and therefore least likely to be reused. + /// + /// + /// + private int GetIndexToUnusedPage(int rowIndex) + { + if (rowIndex > cachePages[0].HighestIndex && + rowIndex > cachePages[1].HighestIndex) + { + int offsetFromPage0 = rowIndex - cachePages[0].HighestIndex; + int offsetFromPage1 = rowIndex - cachePages[1].HighestIndex; + if (offsetFromPage0 < offsetFromPage1) + { + return 1; + } + return 0; + } + else + { + int offsetFromPage0 = cachePages[0].LowestIndex - rowIndex; + int offsetFromPage1 = cachePages[1].LowestIndex - rowIndex; + if (offsetFromPage0 < offsetFromPage1) + { + return 1; + } + return 0; + } + + } + + /// + /// Returns a value indicating whether the given row index is contained + /// in the given DataPage. + /// + /// + /// + /// + private bool IsRowCachedInPage(int pageNumber, int rowIndex) + { + return rowIndex <= cachePages[pageNumber].HighestIndex && + rowIndex >= cachePages[pageNumber].LowestIndex; + } + } + + #endregion + + + #region IDataPageRetriever Interface + + public interface IDataPageRetriever + { + DataTable SupplyPageOfData(int lowerPageBoundary, int rowsPerPage); + } + + #endregion + + + #region DataRetriever Class + + public class DataRetriever : IDataPageRetriever + { + private string tableName; + private SqlCommand command; + + public DataRetriever(string connectionString, string tableName) + { + SqlConnection connection = new SqlConnection(connectionString); + connection.Open(); + command = connection.CreateCommand(); + this.tableName = tableName; + } + + private int rowCountValue = -1; + + public int RowCount + { + get + { + // Return the existing value if it has already been determined. + if (rowCountValue != -1) + { + return rowCountValue; + } + + // Retrieve the row count from the database. + command.CommandText = "SELECT COUNT(*) FROM " + tableName; + rowCountValue = (int)command.ExecuteScalar(); + return rowCountValue; + } + } + + private DataColumnCollection columnsValue; + + public DataColumnCollection Columns + { + get + { + // Return the existing value if it has already been determined. + if (columnsValue != null) + { + return columnsValue; + } + + // Retrieve the column information from the database. + command.CommandText = "SELECT * FROM " + tableName; + SqlDataAdapter adapter = new SqlDataAdapter(); + adapter.SelectCommand = command; + DataTable table = new DataTable(); + table.Locale = System.Globalization.CultureInfo.InvariantCulture; + adapter.FillSchema(table, SchemaType.Source); + columnsValue = table.Columns; + return columnsValue; + } + } + + private string commaSeparatedListOfColumnNamesValue = null; + + private string CommaSeparatedListOfColumnNames + { + get + { + // Return the existing value if it has already been determined. + if (commaSeparatedListOfColumnNamesValue != null) + { + return commaSeparatedListOfColumnNamesValue; + } + + // Store a list of column names for use in the + // SupplyPageOfData method. + System.Text.StringBuilder commaSeparatedColumnNames = + new System.Text.StringBuilder(); + bool firstColumn = true; + foreach (DataColumn column in Columns) + { + if (!firstColumn) + { + commaSeparatedColumnNames.Append(", "); + } + commaSeparatedColumnNames.Append(column.ColumnName); + firstColumn = false; + } + + commaSeparatedListOfColumnNamesValue = + commaSeparatedColumnNames.ToString(); + return commaSeparatedListOfColumnNamesValue; + } + } + + // Declare variables to be reused by the SupplyPageOfData method. + private string columnToSortBy; + private SqlDataAdapter adapter = new SqlDataAdapter(); + + public DataTable SupplyPageOfData(int lowerPageBoundary, int rowsPerPage) + { + // Store the name of the ID column. This column must contain unique + // values so the SQL below will work properly. + if (columnToSortBy == null) + { + columnToSortBy = this.Columns[0].ColumnName; + } + + if (!this.Columns[columnToSortBy].Unique) + { + throw new InvalidOperationException(String.Format( + "Column {0} must contain unique values.", columnToSortBy)); + } + + // Retrieve the specified number of rows from the database, starting + // with the row specified by the lowerPageBoundary parameter. + command.CommandText = "Select Top " + rowsPerPage + " " + + CommaSeparatedListOfColumnNames + " From " + tableName + + " WHERE " + columnToSortBy + " NOT IN (SELECT TOP " + + lowerPageBoundary + " " + columnToSortBy + " From " + + tableName + " Order By " + columnToSortBy + + ") Order By " + columnToSortBy; + adapter.SelectCommand = command; + + DataTable table = new DataTable(); + table.Locale = System.Globalization.CultureInfo.InvariantCulture; + adapter.Fill(table); + return table; + } + + } + + #endregion +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.Designer.cs b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.Designer.cs new file mode 100644 index 00000000000..27a1de15ee3 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.Designer.cs @@ -0,0 +1,76 @@ +namespace CSWinFormDataGridView.JustInTimeDataLoading +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.label1 = new System.Windows.Forms.Label(); + this.dataGridView1 = new System.Windows.Forms.DataGridView(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Verdana", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(19, 21); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(510, 42); + this.label1.TabIndex = 0; + this.label1.Text = resources.GetString("label1.Text"); + // + // dataGridView1 + // + this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dataGridView1.Location = new System.Drawing.Point(22, 89); + this.dataGridView1.Name = "dataGridView1"; + this.dataGridView1.Size = new System.Drawing.Size(596, 381); + this.dataGridView1.TabIndex = 1; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(652, 498); + this.Controls.Add(this.dataGridView1); + this.Controls.Add(this.label1); + this.Name = "MainForm"; + this.Text = "MainForm"; + this.Load += new System.EventHandler(this.MainForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.DataGridView dataGridView1; + } +} \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.cs b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.cs new file mode 100644 index 00000000000..583af660c35 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.cs @@ -0,0 +1,83 @@ +/********************************* Module Header **********************************\ +* Module Name: JustInTimeDataLoading +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* This sample demonstrates how to use virtual mode in the DataGridView control +* with a data cache that loads data from a server only when it is needed. +* This kind of data loading is called "Just-in-time data loading". +\**********************************************************************************/ + +#region Using directives +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Data.SqlClient; +#endregion + + +namespace CSWinFormDataGridView.JustInTimeDataLoading +{ + public partial class MainForm : Form + { + public MainForm() + { + InitializeComponent(); + } + + private Cache memoryCache; + + // Specify a connection string. Replace the given value with a + // valid connection string for a Northwind SQL Server sample + // database accessible to your system. + private string connectionString = + "Initial Catalog=NorthWind;Data Source=localhost;" + + "Integrated Security=SSPI;Persist Security Info=False"; + + private string table = "Orders"; + + private void MainForm_Load(object sender, EventArgs e) + { + // Enable VirtualMode on the DataGridView + this.dataGridView1.VirtualMode = true; + + // Handle the CellValueNeeded event to retrieve the requested cell value + // from the data store or the Customer object currently in edit. + // This event occurs whenever the DataGridView control needs to paint a cell. + this.dataGridView1.CellValueNeeded += new + DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded); + + // Create a DataRetriever and use it to create a Cache object + // and to initialize the DataGridView columns and rows. + try + { + DataRetriever retriever = + new DataRetriever(connectionString, table); + memoryCache = new Cache(retriever, 16); + foreach (DataColumn column in retriever.Columns) + { + dataGridView1.Columns.Add( + column.ColumnName, column.ColumnName); + } + this.dataGridView1.RowCount = retriever.RowCount; + } + catch (SqlException) + { + MessageBox.Show("Connection could not be established. " + + "Verify that the connection string is valid."); + Application.Exit(); + } + } + + private void dataGridView1_CellValueNeeded(object sender, + DataGridViewCellValueEventArgs e) + { + e.Value = memoryCache.RetrieveElement(e.RowIndex, e.ColumnIndex); + } + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.resx b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.resx new file mode 100644 index 00000000000..0956892cbf1 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/MainForm.resx @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + This sample demonstrates how to use virtual mode in the DataGridView control +with a data cache that loads data from a server only when it is needed. +This kind of data loading is called "Just-in-time data loading". + + \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/README.md b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/README.md new file mode 100644 index 00000000000..e0e18a9d413 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/JustInTimeDataLoading/README.md @@ -0,0 +1,39 @@ +# JustInTimeDataLoading Sample + + This sample demonstrates how to use virtual mode in the DataGridView control + with a data cache that loads data from a server only when it is needed. + This kind of data loading is called "Just-in-time data loading". + + +## Remarks + + If you are working with a very large table in a remote database, for example, + you might want to avoid startup delays by retrieving only the data that is + necessary for display and retrieving additional data only when the user scrolls + new rows into view. If the client computers running your application have a + limited amount of memory available for storing data, you might also want to + discard unused data when retrieving new values from the database. + + +## Code Logic + +1. Enable VirtualMode on the DataGridView control by setting the VirtualMode + property to true: + + ```CSharp + this.dataGridView1.VirtualMode = true + ``` + +2. Add columns to the DataGridView according to the data in the database. + +3. Retrieve the row count of the data in the database and set the RowCount + property for the DataGridView. + +4. Handle the CellValueNeeded event to retrieve the requested cell value + from the data store or the Customer object currently in edit. + + +## References + +- [Implementing Virtual Mode with Just-In-Time Data Loading in the Windows + Forms DataGridView Control](https://docs.microsoft.com/dotnet/framework/winforms/controls/implementing-virtual-mode-jit-data-loading-in-the-datagrid) diff --git a/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.Designer.cs b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.Designer.cs new file mode 100644 index 00000000000..9fa1bcc485c --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.Designer.cs @@ -0,0 +1,76 @@ +namespace CSWinFormDataGridView.MultipleLayeredColumnHeader +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.dataGridView1 = new System.Windows.Forms.DataGridView(); + this.label1 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); + this.SuspendLayout(); + // + // dataGridView1 + // + this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dataGridView1.Location = new System.Drawing.Point(22, 54); + this.dataGridView1.Name = "dataGridView1"; + this.dataGridView1.Size = new System.Drawing.Size(621, 389); + this.dataGridView1.TabIndex = 0; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Verdana", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(17, 18); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(626, 16); + this.label1.TabIndex = 1; + this.label1.Text = "This sample demonstrates how to display multiple layer column headers on the Data" + + "GridView."; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(667, 473); + this.Controls.Add(this.label1); + this.Controls.Add(this.dataGridView1); + this.Name = "MainForm"; + this.Text = "MainForm"; + this.Load += new System.EventHandler(this.MainForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.DataGridView dataGridView1; + private System.Windows.Forms.Label label1; + } +} \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.cs b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.cs new file mode 100644 index 00000000000..73b58b38f33 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.cs @@ -0,0 +1,125 @@ +/************************************* Module Header **************************************\ +* Module Name: MultipleLayeredColumnHeader +* Project: CSWinFormDataGridView +* Copyright (c) Microsoft Corporation. +* +* +* This sample demonstrates how to display multiple layer column headers on the DataGridView. +\******************************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace CSWinFormDataGridView.MultipleLayeredColumnHeader +{ + public partial class MainForm : Form + { + public MainForm() + { + InitializeComponent(); + } + + private void MainForm_Load(object sender, EventArgs e) + { + this.dataGridView1.Columns.Add("JanWin", "Win"); + this.dataGridView1.Columns.Add("JanLoss", "Loss"); + this.dataGridView1.Columns.Add("FebWin", "Win"); + this.dataGridView1.Columns.Add("FebLoss", "Loss"); + this.dataGridView1.Columns.Add("MarWin", "Win"); + this.dataGridView1.Columns.Add("MarLoss", "Loss"); + + for (int j = 0; j < this.dataGridView1.ColumnCount; j++) + { + this.dataGridView1.Columns[j].Width = 45; + } + + // Enable resizing on the column headers; + this.dataGridView1.ColumnHeadersHeightSizeMode = + DataGridViewColumnHeadersHeightSizeMode.EnableResizing; + + // Adjust the height for the column headers + this.dataGridView1.ColumnHeadersHeight = + this.dataGridView1.ColumnHeadersHeight * 2; + + // Adjust the text alignment on the column headers to make the text display + // at the center of the bottom; + this.dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = + DataGridViewContentAlignment.BottomCenter; + + // Handle the CellPainting event to draw text for each header cell + this.dataGridView1.CellPainting += new + DataGridViewCellPaintingEventHandler(dataGridView1_CellPainting); + + // Handle the Paint event to draw "merged" header cells; + this.dataGridView1.Paint += new PaintEventHandler(dataGridView1_Paint); + } + + void dataGridView1_Paint(object sender, PaintEventArgs e) + { + // Data for the "merged" header cells + string[] monthes = { "January", "February", "March" }; + + for (int j = 0; j < this.dataGridView1.ColumnCount; ) + { + // Get the column header cell bounds + Rectangle r1 = this.dataGridView1.GetCellDisplayRectangle(j, -1, true); + + r1.X += 1; + r1.Y += 1; + r1.Width = r1.Width * 2 - 2; + r1.Height = r1.Height / 2 - 2; + + using (SolidBrush br = + new SolidBrush( + this.dataGridView1.ColumnHeadersDefaultCellStyle.BackColor)) + { + e.Graphics.FillRectangle(br, r1); + } + + using (Pen p = new Pen(SystemColors.InactiveBorder)) + { + e.Graphics.DrawLine(p, r1.X, r1.Bottom, r1.Right, r1.Bottom); + } + + using( StringFormat format = new StringFormat()) + using (SolidBrush br = + new SolidBrush( + this.dataGridView1.ColumnHeadersDefaultCellStyle.ForeColor)) + { + format.Alignment = StringAlignment.Center; + format.LineAlignment = StringAlignment.Center; + + e.Graphics.DrawString(monthes[j / 2], + this.dataGridView1.ColumnHeadersDefaultCellStyle.Font, + br, + r1, + format); + } + + j += 2; + } + } + + void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) + { + if (e.RowIndex == -1 && e.ColumnIndex > -1) + { + e.PaintBackground(e.CellBounds, false); + + Rectangle r2 = e.CellBounds; + r2.Y += e.CellBounds.Height / 2; + r2.Height = e.CellBounds.Height / 2; + e.PaintContent(r2); + + e.Handled = true; + } + } + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.resx b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.resx new file mode 100644 index 00000000000..19dc0dd8b39 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/MainForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/README.md b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/README.md new file mode 100644 index 00000000000..07038fc4a67 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/MultipleLayeredColumnHeader/README.md @@ -0,0 +1,53 @@ +# MultipleLayeredColumnHeader Sample + +This sample demonstrates how to display multiple layer column headers on the +DataGridView contorl. + +``` +------------------------------------------------------------ +| | January | February | March | +| | Win | Loss | Win | Loss | Win | Loss | +------------------------------------------------------------ +|Team1 | | | | | | | +------------------------------------------------------------ +|Team2 | | | | | | | +------------------------------------------------------------ +|TeamN | | | | | | | +------------------------------------------------------------ +``` + +## Code Logic + +1. Enable resizing on the column headers by setting the + ColumnHeadersHeightSizeMode property as follows: + +```CSharp + this.dataGridView1.ColumnHeadersHeightSizeMode = + DataGridViewColumnHeadersHeightSizeMode.EnableResizing; +``` + +2. Adjust the height for the column headers to make it wide enough for two + layers: + +```CSharp + this.dataGridView1.ColumnHeadersHeight = + this.dataGridView1.ColumnHeadersHeight * 2; +``` + +3. Adjust the text alignment on the column headers to make the text display + at the center of the bottom: + +```CSharp + this.dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = + DataGridViewContentAlignment.BottomCenter; +``` + +4. Handle the DataGridView.CellPainting event to draw text for each header + cell. + +5. Handle the DataGridView.Paint event to draw "merged" header cells. + +## References + +- [DataGridView Class](https://docs.microsoft.com/dotnet/api/system.windows.forms.datagridview) + diff --git a/windowsforms/datagridview/CSWinFormDataGridView/Program.cs b/windowsforms/datagridview/CSWinFormDataGridView/Program.cs new file mode 100644 index 00000000000..3da19adb4a7 --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace CSWinFormDataGridView +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + //Application.Run(new CustomDataGridViewColumn.MainForm()); + //Application.Run(new DataGridViewPaging.MainForm()); + //Application.Run(new EditingControlHosting.MainForm()); + //Application.Run(new JustInTimeDataLoading.MainForm()); + //Application.Run(new MultipleLayeredColumnHeader.MainForm()); + } + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/Properties/AssemblyInfo.cs b/windowsforms/datagridview/CSWinFormDataGridView/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..78113fd17fb --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CSWinFormDataGridView")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft Corporation")] +[assembly: AssemblyProduct("CSWinFormDataGridView")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("46fa4e76-c260-480e-b593-1dcbd6f15fc8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.Designer.cs b/windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.Designer.cs new file mode 100644 index 00000000000..b9af97eda7e --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3053 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace CSWinFormDataGridView.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CSWinFormDataGridView.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.resx b/windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.resx new file mode 100644 index 00000000000..af7dbebbace --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/windowsforms/datagridview/CSWinFormDataGridView/ResourceDeserializationExtensions.cs b/windowsforms/datagridview/CSWinFormDataGridView/ResourceDeserializationExtensions.cs new file mode 100644 index 00000000000..c2f6333f19c --- /dev/null +++ b/windowsforms/datagridview/CSWinFormDataGridView/ResourceDeserializationExtensions.cs @@ -0,0 +1,25 @@ +using System; +using System.Drawing; +using System.IO; +using System.Resources; +using System.Runtime.Serialization.Formatters.Binary; + +namespace CSWinFormDataGridView +{ + public static class ResourceDeserializationExtensions + { + static BinaryFormatter Formatter = new BinaryFormatter(); + + /// + /// Returns an image deserialized from a string resource to work around https://github.com/dotnet/corefx/issues/26745 + /// + public static Image GetImage(this ResourceManager resourceManager, string name) + { + var imageString = resourceManager.GetString(name); + using (var ms = new MemoryStream(Convert.FromBase64String(imageString))) + { + return Image.FromStream(ms); + } + } + } +} diff --git a/windowsforms/datagridview/README.md b/windowsforms/datagridview/README.md new file mode 100644 index 00000000000..48fc91591c5 --- /dev/null +++ b/windowsforms/datagridview/README.md @@ -0,0 +1,26 @@ +# DataGridView Samples +This Windows Forms sample was ported to .NET Core from +[a previous .NET Framework 4.5 sample](https://code.msdn.microsoft.com/windowsdesktop/CSWinFormDataGridView-29783221). + +This sample demonstrates DataGridView usage in a .NET Core 3 WinForms app. +It contains five separate sample DataGridView scenarios. Uncomment the one +you wish to run in `Program.cs`: + +* CustomDataGridViewColumn +* DataGridViewPaging +* EditingControlHosting +* JustInTimeDataLoading +* MultipleLayeredColumnHeader + +Note that the DataGridViewPaging and JustInTimeDataLoading samples use the +NorthWind sample database (in order to have a large amount of data to display +in the grid view). Before running these scenarios, follow the +[these instructions](https://docs.microsoft.com/dotnet/framework/data/adonet/sql/linq/downloading-sample-databases) +to set up the NorthView sample database and make sure that the connection +strings in those scenarios are updated to match where the sample database +is deployed (possibly replacing `localhost` with `(LocalDb)\MSSQLLocalDB`, +for example). + +![Screenshot with paging](images/screenshot1.png) + +![Screenshot with layered column header](images/screenshot2.png) diff --git a/windowsforms/datagridview/images/screenshot1.png b/windowsforms/datagridview/images/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..b88c65c9fd5df43c27874b8c69a83497e14a0635 GIT binary patch literal 34337 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 C?O}=l literal 0 HcmV?d00001 diff --git a/windowsforms/datagridview/images/screenshot2.png b/windowsforms/datagridview/images/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..9bd0bb3c10ee7e90965c654e8b1b013d5e5af777 GIT binary patch literal 8214 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

Date: Tue, 20 Nov 2018 01:01:28 +0800 Subject: [PATCH 2/7] Move snippets to file (#466) * Create rename.cs * Create rename.vb --- snippets/standard/io/file-names/cs/rename.cs | 10 ++++++++++ snippets/standard/io/file-names/vb/rename.vb | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 snippets/standard/io/file-names/cs/rename.cs create mode 100644 snippets/standard/io/file-names/vb/rename.vb diff --git a/snippets/standard/io/file-names/cs/rename.cs b/snippets/standard/io/file-names/cs/rename.cs new file mode 100644 index 00000000000..de55314997f --- /dev/null +++ b/snippets/standard/io/file-names/cs/rename.cs @@ -0,0 +1,10 @@ +using System.IO; + +class Example +{ + static void Main() + { + var fi = new FileInfo(@".\test.txt"); + fi.MoveTo(@".\Test.txt"); + } +} diff --git a/snippets/standard/io/file-names/vb/rename.vb b/snippets/standard/io/file-names/vb/rename.vb new file mode 100644 index 00000000000..cb8ffbddd4a --- /dev/null +++ b/snippets/standard/io/file-names/vb/rename.vb @@ -0,0 +1,8 @@ +Imports System.IO + +Module Example + Public Sub Main() + Dim fi As New FileInfo(".\test.txt") + fi.MoveTo(".\Test.txt") + End Sub +End Module From f39e3e0f26c3c4ae2600a77d06f6540dbefc6e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=AD=E4=B9=9D=E9=BC=8E?= <109224573@qq.com> Date: Tue, 20 Nov 2018 01:07:58 +0800 Subject: [PATCH 3/7] Fix argument (#467) * Update bom1.cs * Update bom1.vb * Update bom1.cs * Update bom1.vb * Update bom1.cs * Update bom1.vb --- .../system.Text.UTF8Encoding Example/CS/bom1.cs | 2 +- .../system.Text.UnicodeEncoding Example/CS/bom1.cs | 2 +- .../system.text.utf32encoding.class/cs/bom1.cs | 2 +- .../system.Text.UTF8Encoding Example/VB/bom1.vb | 2 +- .../system.Text.UnicodeEncoding Example/VB/bom1.vb | 2 +- .../system.text.utf32encoding.class/vb/bom1.vb | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/snippets/csharp/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/CS/bom1.cs b/snippets/csharp/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/CS/bom1.cs index dbf15704e93..2550aea134a 100644 --- a/snippets/csharp/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/CS/bom1.cs +++ b/snippets/csharp/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/CS/bom1.cs @@ -48,7 +48,7 @@ public static void Main() fs.Read(bytes, 0, (int)fs.Length); fs.Close(); - String decodedString = utf8.GetString(encodedBytes); + String decodedString = utf8.GetString(bytes); Console.WriteLine("Decoded bytes:"); Console.WriteLine(decodedString); } diff --git a/snippets/csharp/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/CS/bom1.cs b/snippets/csharp/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/CS/bom1.cs index 709f1469a43..a889f5d8401 100644 --- a/snippets/csharp/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/CS/bom1.cs +++ b/snippets/csharp/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/CS/bom1.cs @@ -46,7 +46,7 @@ public static void Main() fs.Read(bytes, 0, (int)fs.Length); fs.Close(); - String decodedString = unicode.GetString(encodedBytes); + String decodedString = unicode.GetString(bytes); Console.WriteLine("Decoded bytes:"); Console.WriteLine(decodedString); } diff --git a/snippets/csharp/VS_Snippets_CLR_System/system.text.utf32encoding.class/cs/bom1.cs b/snippets/csharp/VS_Snippets_CLR_System/system.text.utf32encoding.class/cs/bom1.cs index 970700b2e8b..259f68f3910 100644 --- a/snippets/csharp/VS_Snippets_CLR_System/system.text.utf32encoding.class/cs/bom1.cs +++ b/snippets/csharp/VS_Snippets_CLR_System/system.text.utf32encoding.class/cs/bom1.cs @@ -45,7 +45,7 @@ public static void Main() fs.Read(bytes, 0, (int)fs.Length); fs.Close(); - String decodedString = enc.GetString(encodedBytes); + String decodedString = enc.GetString(bytes); Console.WriteLine("Decoded bytes from binary file:"); Console.WriteLine(decodedString); } diff --git a/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/VB/bom1.vb b/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/VB/bom1.vb index 5078b9f290d..7b26bfb5443 100644 --- a/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/VB/bom1.vb +++ b/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UTF8Encoding Example/VB/bom1.vb @@ -45,7 +45,7 @@ Class Example fs.Read(bytes, 0, fs.Length) fs.Close() - Dim decodedString As String = utf8.GetString(encodedBytes) + Dim decodedString As String = utf8.GetString(bytes) Console.WriteLine("Decoded bytes:") Console.WriteLine(decodedString) End Sub diff --git a/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/VB/bom1.vb b/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/VB/bom1.vb index 5a426b71067..91572da295c 100644 --- a/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/VB/bom1.vb +++ b/snippets/visualbasic/VS_Snippets_CLR_System/system.Text.UnicodeEncoding Example/VB/bom1.vb @@ -45,7 +45,7 @@ Class Example fs.Read(bytes, 0, fs.Length) fs.Close() - Dim decodedString As String = unicode.GetString(encodedBytes) + Dim decodedString As String = unicode.GetString(bytes) Console.WriteLine("Decoded bytes:") Console.WriteLine(decodedString) End Sub diff --git a/snippets/visualbasic/VS_Snippets_CLR_System/system.text.utf32encoding.class/vb/bom1.vb b/snippets/visualbasic/VS_Snippets_CLR_System/system.text.utf32encoding.class/vb/bom1.vb index cc2ae5b6a8b..0d3d949218e 100644 --- a/snippets/visualbasic/VS_Snippets_CLR_System/system.text.utf32encoding.class/vb/bom1.vb +++ b/snippets/visualbasic/VS_Snippets_CLR_System/system.text.utf32encoding.class/vb/bom1.vb @@ -45,7 +45,7 @@ Class Example fs.Read(bytes, 0, fs.Length) fs.Close() - Dim decodedString As String = enc.GetString(encodedBytes) + Dim decodedString As String = enc.GetString(bytes) Console.WriteLine("Decoded bytes from binary file:") Console.WriteLine(decodedString) End Sub From b2df2818acf1c24ed19b503623b16ffecddff3d6 Mon Sep 17 00:00:00 2001 From: Jonathan Markman Date: Mon, 19 Nov 2018 15:57:41 -0500 Subject: [PATCH 4/7] clarification alignment with PR #9127 (#469) - changed Program.cs to use anonymous object to match markdown snippet - added comment to logging extension method about AppendText behavior --- csharp/getting-started/console-linq/Program.cs | 2 +- csharp/getting-started/console-linq/extensions.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/getting-started/console-linq/Program.cs b/csharp/getting-started/console-linq/Program.cs index bdeea6be777..c853b072892 100644 --- a/csharp/getting-started/console-linq/Program.cs +++ b/csharp/getting-started/console-linq/Program.cs @@ -48,7 +48,7 @@ public static void Main(string[] args) { var startingDeck = (from s in Suits().LogQuery("Suit Generation") from r in Ranks().LogQuery("Value Generation") - select new PlayingCard(s, r)) + select new { Suit = s, Rank = r }) .LogQuery("Starting Deck") .ToArray(); diff --git a/csharp/getting-started/console-linq/extensions.cs b/csharp/getting-started/console-linq/extensions.cs index dfcf0bff44f..5caecad7423 100644 --- a/csharp/getting-started/console-linq/extensions.cs +++ b/csharp/getting-started/console-linq/extensions.cs @@ -43,6 +43,7 @@ public static bool SequenceEquals public static IEnumerable LogQuery (this IEnumerable sequence, string tag) { + // File.AppendText creates a new file if the file doesn't exist. using (var writer = File.AppendText("debug.log")) { writer.WriteLine($"Executing Query {tag}"); From 327c1649178f13aab5cf9482c5332b54736a0ee9 Mon Sep 17 00:00:00 2001 From: Petr Kulikov Date: Mon, 19 Nov 2018 21:58:39 +0100 Subject: [PATCH 5/7] Updated the conditional operator examples (#468) --- .../operators/ConditionalExamples.cs | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/snippets/csharp/language-reference/operators/ConditionalExamples.cs b/snippets/csharp/language-reference/operators/ConditionalExamples.cs index d60373b973d..0931fa643b3 100644 --- a/snippets/csharp/language-reference/operators/ConditionalExamples.cs +++ b/snippets/csharp/language-reference/operators/ConditionalExamples.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace operators { @@ -8,38 +6,62 @@ public class ConditionalExamples { public static void Examples() { + ConditionalRefExpressions(); ConditionalValueExpressions(); + ComparisonWithIf(); } - static void ConditionalRefExpressions() + private static void ConditionalRefExpressions() { // var smallArray = new int[] { 1, 2, 3, 4, 5 }; var largeArray = new int[] { 10, 20, 30, 40, 50 }; - int index= new Random().Next(0, 9); + int index = 7; ref int refValue = ref ((index < 5) ? ref smallArray[index] : ref largeArray[index - 5]); - Console.WriteLine(refValue); + refValue = 0; + + index = 2; + ((index < 5) ? ref smallArray[index] : ref largeArray[index - 5]) = 100; + + Console.WriteLine(string.Join(" ", smallArray)); + Console.WriteLine(string.Join(" ", largeArray)); + // Output: + // 1 2 100 4 5 + // 10 20 0 40 50 // } - - static void ConditionalValueExpressions() + private static void ConditionalValueExpressions() { // - double sinc(double x) => - x != 0.0 ? Math.Sin(x) / x : 1.0; + double sinc(double x) => x != 0.0 ? Math.Sin(x) / x : 1; - Console.WriteLine(sinc(0.2)); Console.WriteLine(sinc(0.1)); Console.WriteLine(sinc(0.0)); - /* - Output: - 0.993346653975306 - 0.998334166468282 - 1 - */ + // Output: + // 0.998334166468282 + // 1 // } + + private static void ComparisonWithIf() + { + // + int input = new Random().Next(-5, 5); + + string classify; + if (input >= 0) + { + classify = "nonnegative"; + } + else + { + classify = "negative"; + } + + classify = (input >= 0) ? "nonnegative" : "negative"; + // + } } } From 2dc0f4ba595351b1ec6d3e507024158e2780ec40 Mon Sep 17 00:00:00 2001 From: Mikkel Nylander Bundgaard Date: Tue, 20 Nov 2018 01:00:43 +0100 Subject: [PATCH 6/7] Correct LinkedList constructor examples (#470) Corrected formatting in examples and code vs expected output. Fixes dotnet/docs#9113 --- .../CPP/llctor.cpp | 46 +++++++++---------- .../CS/llctor.cs | 46 +++++++++---------- .../VB/llctor.vb | 6 +-- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/snippets/cpp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CPP/llctor.cpp b/snippets/cpp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CPP/llctor.cpp index 72b02253198..3533f81fe87 100644 --- a/snippets/cpp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CPP/llctor.cpp +++ b/snippets/cpp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CPP/llctor.cpp @@ -9,29 +9,29 @@ using namespace System::Collections::Generic; void main() { - // Create and initialize a new LinkedList. - LinkedList< String^ > ^ ll = gcnew LinkedList< String^ >; - ll->AddLast( L"red" ); - ll->AddLast( L"orange" ); - ll->AddLast( L"yellow" ); - ll->AddLast( L"orange" ); - - // Display the contents of the LinkedList. - if ( ll->Count > 0 ) - { - Console::WriteLine( L"The first item in the list is {0}.", ll->First->Value ); - Console::WriteLine( L"The last item in the list is {0}.", ll->Last->Value ); - Console::WriteLine( L"The LinkedList contains:" ); - - for each (String^ s in ll) - { - Console::WriteLine( L" {0}", s ); - } - } - else - { - Console::WriteLine( L"The LinkedList is empty." ); - } + // Create and initialize a new LinkedList. + LinkedList< String^ > ^ ll = gcnew LinkedList< String^ >; + ll->AddLast(L"red"); + ll->AddLast(L"orange"); + ll->AddLast(L"yellow"); + ll->AddLast(L"orange"); + + // Display the contents of the LinkedList. + if (ll->Count > 0) + { + Console::WriteLine(L"The first item in the list is {0}.", ll->First->Value); + Console::WriteLine(L"The last item in the list is {0}.", ll->Last->Value); + Console::WriteLine(L"The LinkedList contains:"); + + for each (String^ s in ll) + { + Console::WriteLine(L" {0}", s); + } + } + else + { + Console::WriteLine(L"The LinkedList is empty."); + } } /* This code produces the following output. diff --git a/snippets/csharp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CS/llctor.cs b/snippets/csharp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CS/llctor.cs index afdd8720ec8..2989590f66d 100644 --- a/snippets/csharp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CS/llctor.cs +++ b/snippets/csharp/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/CS/llctor.cs @@ -6,32 +6,32 @@ using System.Collections; using System.Collections.Generic; -public class GenericCollection +public class GenericCollection { - public static void Main() - { - // Create and initialize a new LinkedList. - LinkedList ll = new LinkedList(); - ll.AddLast( "red" ); - ll.AddLast( "orange" ); - ll.AddLast( "yellow" ); - ll.AddLast( "orange" ); + public static void Main() + { + // Create and initialize a new LinkedList. + LinkedList ll = new LinkedList(); + ll.AddLast("red"); + ll.AddLast("orange"); + ll.AddLast("yellow"); + ll.AddLast("orange"); - // Display the contents of the LinkedList. - if ( ll.Count > 0 ) - { - Console.WriteLine( "The item in the list is {0}.", ll.First.Value ); - Console.WriteLine( "The item in the list is {0}.", ll.Last.Value ); + // Display the contents of the LinkedList. + if (ll.Count > 0) + { + Console.WriteLine("The first item in the list is {0}.", ll.First.Value); + Console.WriteLine("The last item in the list is {0}.", ll.Last.Value); - Console.WriteLine( "The LinkedList contains:" ); - foreach ( String s in ll ) - Console.WriteLine( " {0}", s); - } - else - { - Console.WriteLine("The LinkedList is empty."); - } - } + Console.WriteLine("The LinkedList contains:"); + foreach (String s in ll) + Console.WriteLine(" {0}", s); + } + else + { + Console.WriteLine("The LinkedList is empty."); + } + } } /* This code produces the following output. diff --git a/snippets/visualbasic/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/VB/llctor.vb b/snippets/visualbasic/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/VB/llctor.vb index 62852dbd7ac..a5b4d5a4704 100644 --- a/snippets/visualbasic/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/VB/llctor.vb +++ b/snippets/visualbasic/VS_Snippets_CLR_System/system.Collections.Generic.LinkedList.ctor/VB/llctor.vb @@ -31,11 +31,11 @@ Public Class GenericCollection End Sub -End Class +End Class 'This code produces the following output. ' -'The first item in the list is . +'The first item in the list is red. 'The last item in the list is orange. 'The LinkedList contains: ' red @@ -43,4 +43,4 @@ End Class ' yellow ' orange -' \ No newline at end of file +' From 8e0806148f843cc7f8602d04b0ab4d8579c11d03 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 19 Nov 2018 20:17:17 -0500 Subject: [PATCH 7/7] remove outdated Docker tutorial (#471) It was written before many of our .NET Core based tools, and is not helpful to users. --- .../WeatherMicroservice/.dockerignore | 3 - .../WeatherMicroservice/.gitignore | 11 --- .../WeatherMicroservice/Dockerfile | 16 ----- .../WeatherMicroservice/Extensions.cs | 19 ------ .../WeatherMicroservice/Program.cs | 24 ------- .../Properties/launchSettings.json | 27 -------- .../WeatherMicroservice/Startup.cs | 67 ------------------- .../WeatherMicroservice.csproj | 16 ----- .../WeatherMicroservice/WeatherReport.cs | 36 ---------- 9 files changed, 219 deletions(-) delete mode 100644 csharp/getting-started/WeatherMicroservice/.dockerignore delete mode 100644 csharp/getting-started/WeatherMicroservice/.gitignore delete mode 100644 csharp/getting-started/WeatherMicroservice/Dockerfile delete mode 100644 csharp/getting-started/WeatherMicroservice/Extensions.cs delete mode 100644 csharp/getting-started/WeatherMicroservice/Program.cs delete mode 100644 csharp/getting-started/WeatherMicroservice/Properties/launchSettings.json delete mode 100644 csharp/getting-started/WeatherMicroservice/Startup.cs delete mode 100644 csharp/getting-started/WeatherMicroservice/WeatherMicroservice.csproj delete mode 100644 csharp/getting-started/WeatherMicroservice/WeatherReport.cs diff --git a/csharp/getting-started/WeatherMicroservice/.dockerignore b/csharp/getting-started/WeatherMicroservice/.dockerignore deleted file mode 100644 index 69101bde306..00000000000 --- a/csharp/getting-started/WeatherMicroservice/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -bin/* -obj/* -out/* diff --git a/csharp/getting-started/WeatherMicroservice/.gitignore b/csharp/getting-started/WeatherMicroservice/.gitignore deleted file mode 100644 index 9d5c7340f09..00000000000 --- a/csharp/getting-started/WeatherMicroservice/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# User-specific files -*.suo -*.user - -# Build results -bin/ -obj/ -out/ - -# Visual Studio cache/options directory -.vs/ \ No newline at end of file diff --git a/csharp/getting-started/WeatherMicroservice/Dockerfile b/csharp/getting-started/WeatherMicroservice/Dockerfile deleted file mode 100644 index cded7f50db8..00000000000 --- a/csharp/getting-started/WeatherMicroservice/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM microsoft/dotnet:2.1-sdk AS build -WORKDIR /app - -# Copy csproj and restore as distinct layers -COPY *.csproj ./ -RUN dotnet restore - -# Copy everything else and build -COPY . ./ -RUN dotnet publish -c Release -o out - -# Build runtime image -FROM microsoft/dotnet:2.1-aspnetcore-runtime -WORKDIR /app -COPY --from=build /app/out . -ENTRYPOINT ["dotnet", "WeatherMicroservice.dll"] \ No newline at end of file diff --git a/csharp/getting-started/WeatherMicroservice/Extensions.cs b/csharp/getting-started/WeatherMicroservice/Extensions.cs deleted file mode 100644 index ab5a7695e86..00000000000 --- a/csharp/getting-started/WeatherMicroservice/Extensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace WeatherMicroservice -{ -#region TryParseExtension - public static class Extensions - { - public static double? TryParse(this string input) - { - if (double.TryParse(input, out var result)) - { - return result; - } - else - { - return null; - } - } - } -#endregion -} \ No newline at end of file diff --git a/csharp/getting-started/WeatherMicroservice/Program.cs b/csharp/getting-started/WeatherMicroservice/Program.cs deleted file mode 100644 index d3815744f0c..00000000000 --- a/csharp/getting-started/WeatherMicroservice/Program.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; - -namespace WeatherMicroservice -{ - public class Program - { - public static void Main(string[] args) - { - CreateWebHostBuilder(args).Build().Run(); - } - - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup(); - } -} diff --git a/csharp/getting-started/WeatherMicroservice/Properties/launchSettings.json b/csharp/getting-started/WeatherMicroservice/Properties/launchSettings.json deleted file mode 100644 index 4c1bacefd81..00000000000 --- a/csharp/getting-started/WeatherMicroservice/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:54554", - "sslPort": 44382 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "WeatherMicroservice": { - "commandName": "Project", - "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} \ No newline at end of file diff --git a/csharp/getting-started/WeatherMicroservice/Startup.cs b/csharp/getting-started/WeatherMicroservice/Startup.cs deleted file mode 100644 index 28b0d497842..00000000000 --- a/csharp/getting-started/WeatherMicroservice/Startup.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; - -namespace WeatherMicroservice -{ - public class Startup - { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.Run(async (context) => - { -#region SetCulture - CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; -#endregion -#region ReadQueryString - var latString = context.Request.Query["lat"].FirstOrDefault(); - var longString = context.Request.Query["long"].FirstOrDefault(); -#endregion -#region UseTryParse - var latitude = latString.TryParse(); - var longitude = longString.TryParse(); -#endregion -#region GenerateRandomReport - if (latitude.HasValue && longitude.HasValue) - { - var forecast = new List(); - for (var days = 1; days <= 5; days++) - { - forecast.Add(new WeatherReport(latitude.Value, longitude.Value, days)); - } -#region ConvertToJSON - var json = JsonConvert.SerializeObject(forecast, Formatting.Indented); - context.Response.ContentType = "application/json; charset=utf-8"; - await context.Response.WriteAsync(json); -#endregion - } -#endregion - else - { -#region WriteResponse - await context.Response.WriteAsync($"Retrieving Weather for lat: {latitude}, long: {longitude}"); -#endregion - } - }); - } - } -} diff --git a/csharp/getting-started/WeatherMicroservice/WeatherMicroservice.csproj b/csharp/getting-started/WeatherMicroservice/WeatherMicroservice.csproj deleted file mode 100644 index 276e8640f7d..00000000000 --- a/csharp/getting-started/WeatherMicroservice/WeatherMicroservice.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netcoreapp2.1 - - - - - - - - - - - - diff --git a/csharp/getting-started/WeatherMicroservice/WeatherReport.cs b/csharp/getting-started/WeatherMicroservice/WeatherReport.cs deleted file mode 100644 index 768f9eb84a8..00000000000 --- a/csharp/getting-started/WeatherMicroservice/WeatherReport.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; - -namespace WeatherMicroservice -{ -#region WeatherReport - public class WeatherReport - { - private static readonly string[] PossibleConditions = - { - "Sunny", - "Mostly Sunny", - "Partly Sunny", - "Partly Cloudy", - "Mostly Cloudy", - "Rain" - }; - -#region WeatherReportConstructor - public WeatherReport(double latitude, double longitude, int daysInFuture) - { - var generator = new Random((int)(latitude + longitude) + daysInFuture); - - HighTemperatureFahrenheit = generator.Next(40, 100); - LowTemperatureFahrenheit = generator.Next(0, HighTemperatureFahrenheit); - AverageWindSpeedMph = generator.Next(0, 45); - Condition = PossibleConditions[generator.Next(0, PossibleConditions.Length - 1)]; - } -#endregion - - public int HighTemperatureFahrenheit { get; } - public int LowTemperatureFahrenheit { get; } - public int AverageWindSpeedMph { get; } - public string Condition { get; } - } -#endregion -}