C# WinApp DataGridView ต้องการใส่การคำนวณใน DataGridView ครับ
ผมต้องการให้ผู้ใช้งานใส่สูตรในเซลล์ จากนั้นก็คำนวณ ได้เลย ครับ
โดย DataGridView ผูกอยู่กับ BindingSource
ผมลองทำ 3 แบบ คือ
1. ใช้ DataGridViewTextBoxColumn และ CellEndEdit
Code (C#)
private void aLS_F_711DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = sender as DataGridView;
if (dgv[1, e.RowIndex].Value == null || string.IsNullOrEmpty(dgv[1, e.RowIndex].Value.ToString()))
{
dgv[1, e.RowIndex].Value = f711Item;
}
if (e.ColumnIndex == 3)
{
string value = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
if (value.StartsWith("="))
{
string expression = value.Substring(1); // เอาเฉพาะส่วนที่ต้องการคำนวณ
// คำนวณ
DataTable table = new DataTable();
var result = table.Compute(expression, "");
MessageBox.Show(result.ToString());
dgv[3, e.RowIndex].Value = result;
}
}
}
ผลคือ พิมพ์แล้ว คลิกอะไรไม่ได้เลย ต้องปิดโปรแกรมอย่างเดียว
แต่ถ้าไม่ผูกกับ BindingSource ก็ใช้ได้ปกติ
2. เขียนคลาส ขึ้นมาใช้งาน
Code (C#)
#region _DataGridViewCalColumn
public class DataGridViewCalColumn : DataGridViewColumn
{
public DataGridViewCalColumn()
: base(new DataGridViewCalCell())
{
}
public override DataGridViewCell CellTemplate
{
get { return base.CellTemplate; }
set
{
if (!(value is DataGridViewCalCell))
throw new InvalidCastException("Must be a DataGridViewCalCell");
base.CellTemplate = value;
}
}
}
internal class DataGridViewCalCell : DataGridViewTextBoxCell
{
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
}
protected override void OnLeave(int rowIndex, bool throughMouseClick)
{
base.OnLeave(rowIndex, throughMouseClick);
if ((!object.ReferenceEquals(this.Value, DBNull.Value)) && (this.Value != null))
{
string value = this.Value.ToString();
string expression = (value.StartsWith("=")) ? value.Substring(1) : value; // เอาเฉพาะส่วนที่ต้องการคำนวณ
var result = new DataTable().Compute(expression, "");
this.Value =result.ToString();
}
if (DataGridView != null)DataGridView.EndEdit();
}
public override Type EditType => typeof(DataGridViewCalEdit);
public override Type ValueType => typeof(string);
}
internal class DataGridViewCalEdit : TextBox, IDataGridViewEditingControl
{
private DataGridView dataGridViewControl;
private bool valueIsChanged = false;
private int rowIndexNum;
public object EditingControlFormattedValue
{
get => Text;
set
{
if (value is string str)
Text = str;
}
}
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) => Text;
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) => Font = dataGridViewCellStyle.Font;
public int EditingControlRowIndex
{
get => rowIndexNum;
set => rowIndexNum = value;
}
public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
{
switch (key & Keys.KeyCode)
{
case Keys.Left:
case Keys.Up:
case Keys.Down:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.PageDown:
case Keys.PageUp:
return true;
default:
return false;
}
}
public void PrepareEditingControlForEdit(bool selectAll)
{
}
public bool RepositionEditingControlOnValueChange => false;
public DataGridView EditingControlDataGridView
{
get => dataGridViewControl;
set => dataGridViewControl = value;
}
public bool EditingControlValueChanged
{
get => valueIsChanged;
set => valueIsChanged = value;
}
public Cursor EditingControlCursor => Cursor;
Cursor IDataGridViewEditingControl.EditingPanelCursor => EditingControlCursor;
protected override void OnTextChanged(EventArgs e)
{
valueIsChanged = true;
EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnTextChanged(e);
}
}
#endregion
ใช้ DataGridViewCalColumn ก็ค้างเหมือนเดิม ถ้าไม่ผูกกับ BindingSource ก็ใช้ได้ปกติ ก็ใช้ได้เหมือนเดิม
3. เพิ่ม Edit เข้ามา
Code (C#)
#region _DataGridViewCal_NewColumn
/// <summary>
/// Hosts a collection of DataGridViewTextBoxCell cells.
/// </summary>
public class DataGridViewCal_NewColumn : DataGridViewColumn
{
// public enum PathType { directory, file };
//public PathType pathtype = PathType.file;
public DataGridViewCal_NewColumn()
: base(new DataGridViewCal_NewCell())
{
}
private bool _showbutton = true;
[System.ComponentModel.Browsable(true)]
[System.ComponentModel.Category("TOR Setting")]
[System.ComponentModel.Description("Disible/Enable Button")]
public bool ShowButton
{
get { return _showbutton; }
set
{
_showbutton = value;
}
}
public override object Clone()
{
var clm = base.Clone() as DataGridViewCal_NewColumn;
DataGridViewCal_NewColumn xxx = base.Clone() as DataGridViewCal_NewColumn;
if (clm != null)
{
clm.ShowButton = _showbutton;
}
return clm;
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
if (null != value &&
!value.GetType().IsAssignableFrom(typeof(DataGridViewCal_NewCell)))
{
throw new InvalidCastException("must be a DataGridViewCal_NewCell");
}
base.CellTemplate = value;
}
}
}
/// <summary>
/// Displays editable text information in a DataGridView control. Uses
/// PathEllipsis formatting if the column is smaller than the width of a
/// displayed filesystem path.
/// </summary>
public class DataGridViewCal_NewCell : DataGridViewTextBoxCell
{
Button browseButton;
Dictionary<Color, SolidBrush> brushes = new Dictionary<Color, SolidBrush>();
protected virtual SolidBrush GetCachedBrush(Color color)
{
if (this.brushes.ContainsKey(color))
return this.brushes[color];
SolidBrush brush = new SolidBrush(color);
this.brushes.Add(color, brush);
return brush;
}
protected virtual bool RightToLeftInternal
{
get
{
return this.DataGridView.RightToLeft == RightToLeft.Yes;
}
}
protected override void OnLeave(int rowIndex, bool throughMouseClick)
{
base.OnLeave(rowIndex, throughMouseClick);
browseButton.Hide();
}
protected override void OnEnter(int rowIndex, bool throughMouseClick)
{
browseButton.Hide();
base.OnEnter(rowIndex, throughMouseClick);
DataGridViewCal_NewColumn calColumn = (DataGridViewCal_NewColumn)this.DataGridView.Columns[ColumnIndex];
if (RowIndex < 0 || !calColumn.ShowButton) return;
Rectangle Loc;
int Wid;
Loc = this.DataGridView.GetCellDisplayRectangle(ColumnIndex, RowIndex, false);
Wid = this.DataGridView.CurrentCell.Size.Width;
browseButton.Location = new Point(Loc.X - 25 + Wid, Loc.Y - 4);
browseButton.Height = this.DataGridView.CurrentCell.Size.Height + 4;
browseButton.Width = browseButton.Height;
if (!this.DataGridView.Controls.Contains(browseButton))
this.DataGridView.Controls.Add(browseButton);
browseButton.Show();
}
public bool ShowFocusCues
{
get { return true; }
}
protected bool ApplyVisualStylesToHeaders
{
get
{
if (Application.RenderWithVisualStyles)
{
return this.DataGridView.EnableHeadersVisualStyles;
}
return false;
}
}
public DataGridViewCal_NewCell()
: base()
{
browseButton = new Button();
// browseButton.FlatStyle = FlatStyle.Flat;
browseButton.FlatAppearance.BorderSize = 0;
browseButton.Size = new Size(30, 25);
browseButton.ImageAlign = ContentAlignment.MiddleCenter;
browseButton.FlatAppearance.MouseDownBackColor = Color.Transparent;
browseButton.FlatAppearance.MouseOverBackColor = Color.Transparent;
browseButton.BackColor = Color.Transparent;
browseButton.Text = "...";
browseButton.Hide();
browseButton.Click += (o, e) => {
DataGridViewCal_NewColumn filePathColumn = (DataGridViewCal_NewColumn)this.DataGridView.Columns[ColumnIndex];
EditCell cell = new EditCell();
if (cell.ShowDialog() == DialogResult.OK)
{
if (!string.IsNullOrEmpty(cell.Value))
{
base.Value = cell.Value;
}
}
};
}
}
#endregion
internal partial class EditCell : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.txt = new System.Windows.Forms.TextBox();
this.btnOK = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(19, 9);
this.label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(116, 25);
this.label1.TabIndex = 0;
this.label1.Text = "Cell Value:";
//
// txt
//
this.txt.Location = new System.Drawing.Point(88, 49);
this.txt.Margin = new System.Windows.Forms.Padding(6);
this.txt.Name = "txt";
this.txt.Size = new System.Drawing.Size(386, 31);
this.txt.TabIndex = 1;
this.txt.KeyDown += new System.Windows.Forms.KeyEventHandler(this.txt_KeyDown);
//
// btnOK
//
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(387, 115);
this.btnOK.Margin = new System.Windows.Forms.Padding(6);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(150, 44);
this.btnOK.TabIndex = 2;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(24, 115);
this.btnCancel.Margin = new System.Windows.Forms.Padding(6);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(150, 44);
this.btnCancel.TabIndex = 3;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// EditCell
//
this.AcceptButton = this.btnOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(552, 174);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOK);
this.Controls.Add(this.txt);
this.Controls.Add(this.label1);
this.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(222)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Margin = new System.Windows.Forms.Padding(6);
this.Name = "EditCell";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Edit Cell Value";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox txt;
private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel;
public EditCell()
{
InitializeComponent();
}
public string Value
{
get { return txt.Text; }
set { txt.Text = value; }
}
private void btnOK_Click(object sender, System.EventArgs e)
{
Cal();
}
private void btnCancel_Click(object sender, EventArgs e)
{
Close();
}
private void txt_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter) Cal();
}
void Cal()
{
string expression = txt.Text;
if (txt.Text.StartsWith("="))
{
expression = txt.Text.Substring(1);
}
// คำนวณ
DataTable table = new DataTable();
var result = table.Compute(expression, "");
Value = result.ToString();
Close();
}
}
มีการคำนวณให้จริง แต่ ไม่เพิ่มแถวให้เหมือน Endedit ครับ
ผมไม่รู้จะเอาตัวไหนมาแก้ดี
ใจผมคือ ไม่อยากได้ปุ่มกดครับ ผมว่า ถ้าพิมพ์ในเซลล์เลยน่าจะเหมาะกว่า
หรือ ถ้าเป็นปุ่มกด แล้ว จะเรียกใช้ หรือ ให้เพิ่มแถว เหมือนที่เราพิมพ์ในเซลล์ได้อย่างไรครับTag : .NET, Win (Windows App), C#
Date :
2023-07-19 09:59:48
By :
lamaka.tor
View :
352
Reply :
5
ทำได้แล้วครับ
Code (C#)
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
namespace TORServices.Forms.Datagridviews
{
#region _MathDataGridViewColumn
public class MathDataGridViewColumn : DataGridViewColumn
{
public MathDataGridViewColumn()
: base(new MathDataGridViewCell())
{
}
public override DataGridViewCell CellTemplate
{
get { return base.CellTemplate; }
set
{
if ((value != null) && !value.GetType().IsAssignableFrom(typeof(MathDataGridViewCell)))
{
throw new InvalidCastException("Must be a MathDataGridViewCell");
}
base.CellTemplate = value;
}
}
}
public class MathDataGridViewCell : DataGridViewTextBoxCell
{
public MathDataGridViewCell()
{
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// Set the value of the editing control to the current cell value.
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
MathDataGridViewEdit ctl = (MathDataGridViewEdit)DataGridView.EditingControl;
if ((!object.ReferenceEquals(this.Value, DBNull.Value)))
{
if ((this.Value != null))
{
ctl.Text = "";// this.Value.ToString();
}
}
}
public override Type EditType
{
// Return the type of the editing contol that MathDataGridViewCell uses.
get { return typeof(MathDataGridViewEdit); }
}
public override Type ValueType
{
// Return the type of the value that MathDataGridViewCell contains.
get { return typeof(string); }
}
}
class MathDataGridViewEdit : TextBox, IDataGridViewEditingControl
{
private DataGridView dataGridViewControl;
private bool valueIsChanged = false;
private int rowIndexNum;
public MathDataGridViewEdit()
{
// this.Format = DateCalendarPickerFormat.Short;
}
public object EditingControlFormattedValue
{
get { return this.Text; }
set
{
if (value is String)
{
// MessageBox.Show(this.Format.ToString());
this.Text = value.ToString();
}
}
}
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return this.Text;
}
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
this.Font = dataGridViewCellStyle.Font;
}
public int EditingControlRowIndex
{
get { return rowIndexNum; }
set { rowIndexNum = value; }
}
public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
{
// Let the DateCalendarPicker handle the keys listed.
switch (key & Keys.KeyCode)
{
case Keys.Left:
case Keys.Up:
case Keys.Down:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.PageDown:
case Keys.PageUp:
return true;
default:
return false;
}
}
public void PrepareEditingControlForEdit(bool selectAll)
{
// No preparation needs to be done.
}
public bool RepositionEditingControlOnValueChange
{
get { return false; }
}
public DataGridView EditingControlDataGridView
{
get { return dataGridViewControl; }
set { dataGridViewControl = value; }
}
public bool EditingControlValueChanged
{
get { return valueIsChanged; }
set { valueIsChanged = value; }
}
public Cursor EditingControlCursor
{
get { return base.Cursor; }
}
Cursor IDataGridViewEditingControl.EditingPanelCursor
{
get { return EditingControlCursor; }
}
protected override void OnTextChanged(EventArgs e)
{
valueIsChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnTextChanged(e);
}
protected override void OnLeave(EventArgs e)
{
string expression = this.Text;
if (this.Text.StartsWith("="))
{
expression = this.Text.Substring(1); // เอาเฉพาะส่วนที่ต้องการคำนวณ
}
// คำนวณ
DataTable table = new DataTable();
var result = table.Compute(expression, "");
// แสดงผลลัพธ์ใน MessageBox หรือทำอย่างอื่นตามที่คุณต้องการ
this.Text = result.ToString();
base.OnLeave(e);
}
}
#endregion
}
แต่น้องที่ทำงานบอกว่า อยากได้เป็นแบบ Dialog มันดูง่ายดี เลยเปลี่ยนมาเป็น Dialog ครับ
Date :
2023-07-26 10:14:04
By :
lamaka.tor
Code (C#)
แต่น้องที่ทำงานบอกว่า อยากได้เป็นแบบ Dialog มันดูง่ายดี เลยเปลี่ยนมาเป็น Dialog ครับ
นายก็ยังเป็นเด็กน้อยเหมือนเดิม (รออายุ 55 ปี)
...
Date :
2023-07-29 17:46:33
By :
ผ่านมา
นายมองเหมือนเด็กมองหะมอยมองตัวเอง
เราเห็นหมดอทิเช่น Dart/Flutter/ etc...
Date :
2023-07-29 17:54:16
By :
ผ่านมา
อายุปูนนี้แล้ว ลองผิดลองถูกไม่ได้หรอก
เราเห็นนายไปเล่น Mobile/Java/etc...
ปล. เราเคารพนับถือท่าน Chinahan เรายังคงเส้นคงวาเคารพนับถือท่าน
Date :
2023-07-29 18:06:31
By :
ผ่านมา
Load balance : Server 05