我有一个员工评估计划(C#WinForm),经理应该看到他们的员工并根据某些标准对他们进行评分。简化的数据库图如图1所示 enter image description here
表格定义:
Prs:人员(员工)
工作:人员工作
发布:Prs和Job的加入表(因为他们有多对多的关系)
SubCrt:评估员工的标准
评分:应保存员工分数的表
必要的描述:
- 评估每3个月进行一次(称为季节)
- 每项工作的标准与其他工作不同
- 每个员工在一个季节可能有一个以上的职位(因为工作变化)。所以我们必须处理它的结果
WinForm如图2所示。
方案:
- 经理选择一份工作
- DataGridView 将基于ComboBox的选定作业 填充,如图3所示。
我的主要问题是如何在 DataGridView 中实现可用于 数据输入 的表格(插入,更新,删除分数)?
您对DB,它的关系,C#表格和...的额外想法和建议将不胜感激 此致
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Scoring_Form
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
DataClasses1DataContext db = new DataClasses1DataContext();
public int rows(int JobId)
{
var row = from crt in db.SubCrts
join job in db.Jobs
on crt.JobId equals job.JobId
where job.JobId == JobId
select crt.JobId;
return row.Count();
}
public int columns(int JobId)
{
var Col = from prs in db.Prs
join post in db.Posts
on prs.PrsId equals post.PrsId
join job in db.Jobs
on post.JobId equals job.JobId
where job.JobId == JobId
select prs.PrsId;
return Col.Count();
}
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.DataSource = db.Jobs.ToList();
comboBox1.DisplayMember = "JobTitle";
comboBox1.ValueMember = "JobId";
//===================================================
string[] PrsID = new string[columns(Convert.ToInt32(comboBox1.SelectedValue)) - 1];
string[] PrsName = new string[columns(Convert.ToInt32(comboBox1.SelectedValue)) - 1];
string[] CrtID = new string[rows(Convert.ToInt32(comboBox1.SelectedValue)) - 1];
string[] CrtName = new string[rows(Convert.ToInt32(comboBox1.SelectedValue)) - 1];
string[,] tbl = new string[rows(Convert.ToInt32(comboBox1.SelectedValue))+2,
columns(Convert.ToInt32(comboBox1.SelectedValue))+2];
for (int i = 0; i < columns(Convert.ToInt32(comboBox1.SelectedValue)) - 1; i++)
{
var a = from prs in db.Prs
join post in db.Posts
on prs.PrsId equals post.PrsId
join job in db.Jobs
on post.JobId equals job.JobId
select prs.PrsId;
PrsID[i] = a.ElementAt(i).ToString();
var b = from prs in db.Prs
select (prs.FName + ' ' + prs.LName).ToString();
PrsName[i] = b.ElementAt(i);
}
for (int j = 0; j < rows(Convert.ToInt32(comboBox1.SelectedValue)) - 1; j++)
{
var c = from crt in db.SubCrts
join job in db.Jobs
on crt.JobId equals job.JobId
select crt.SubCId;
CrtID[j] = c.ElementAt(j).ToString();
var d = from crt in db.SubCrts
select crt.Title;
CrtName[j] = d.ElementAt(j);
}
tbl[0, 0] = ""; tbl[0, 1] = ""; tbl[1, 0] = ""; tbl[1, 1] = "";
for (int l = 2; l < columns(Convert.ToInt32(comboBox1.SelectedValue)) + 1; l++)
{
for (int m = 2; m < rows(Convert.ToInt32(comboBox1.SelectedValue)) + 1; m++)
{
tbl[0, l] = PrsID.ElementAt(l - 2);
tbl[1, l] = PrsName.ElementAt(l - 2);
tbl[m, 0] = CrtID.ElementAt(m - 2);
tbl[m, 1] = CrtName.ElementAt(m - 2);
var h = from sss in db.Scorings
where sss.PrsId == Convert.ToInt32(tbl[0, l])
where sss.SubCId == Convert.ToInt32(tbl[m, 0])
select sss.Score;
tbl[l, m] = h.ElementAt(0).ToString();
}
}
dataGridView1.DataSource = tbl;
}
}
}
在做了一些搜索之后,我发现了Rob Sedgwick将一维数组转换为数据表的代码安静
public DataTable ConvertArrayToDatatable(MarketUnit[] arrList)
{
DataTable dt = new DataTable();
try
{
if (arrList.Count() > 0)
{
Type arrype = arrList[0].GetType();
dt = new DataTable(arrype.Name);
foreach (PropertyInfo propInfo in arrype.GetProperties())
{
dt.Columns.Add(new DataColumn(propInfo.Name));
}
foreach (object obj in arrList)
{
DataRow dr = dt.NewRow();
foreach (DataColumn dc in dt.Columns)
{
dr[dc.ColumnName] = obj.GetType().GetProperty(dc.ColumnName).GetValue(obj, null);
}
dt.Rows.Add(dr);
}
}
return dt;
}
catch (Exception ex)
{
return dt;
}
}
是否可以将其更改为用于我的2D数组(Tbl)?
答案 0 :(得分:0)
正如我的评论所述......你的问题范围很广。有许多方法可以实现创建此“员工评估”表单的目标。所以我希望这个答案至少可以帮助构建和管理用作DataTable
到DataSource
的{{1}}。我的回答演示了如何过滤DataGridView
,以便DataTable
只显示符合过滤条件或按多个条件过滤的项目...即过滤DataGridView
对作业类型的选择。请注意,这与基本相同,并使用Manager
的{{1}}属性来实现此过滤。这个RowFilter
有些限制,如果数据与原始数据库解耦,CRUD功能可能会成为您的问题。所以仅以此为例。
您发布的代码似乎比以前更加困难。以下示例中所有DataTable
和RowFilter
的{{1}}为DataSource
!。发布的代码坚持将数据源转换为字符串数组是不必要的。
我使用的方法与数据库图片显示的方法不同。有四(4)DataGridViews
:ComboBoxes
,用作DATATABLES
DataTables
的数据源; employeesDT
数据表用作DataGridView
dgvEmployees
的数据源; jobsCBDT
用作ComboBox
cbJobs
的数据源; managersCBDT
用作ComboBox
cbManagers
的数据源。
我的方法把它分解为三个主要的“对象”:一个“员工”对象,可能是一个经理。这个“Employee”对象有一个额外的布尔属性来指示员工是否是经理; “作业”对象,定义不同的“作业”类型;最后是“评价”对象。此“评估”类将具有以下属性。您可以在不使用课程的情况下完成此操作,但我建议您考虑它们的用途。但evaluationsDT
是必要的。
DataGridView
以下是此dgvEvaluations
课程的DataTable
定义。
public class Evaluation {
public int ID { get; set; }
public Employee EmployeeEvaluated { get; set; }
public Employee EvaluatingManager { get; set; }
public Job JobEvaluated { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public double PersonalScore { get; set; }
public double ImpactScore { get; set; }
public double CommunicationScore { get; set; }
public double DecisionMakingScore { get; set; }
public double KnowledgeSkillsScore { get; set; }
public double CareerDevelopmentScore { get; set; }
public double InterpersonalScore { get; set; }
public Evaluation() { }
}
此帖子中似乎缺少此“评估”结构。这是一项评估,员工可以进行多项评估。发布的图片中的图3似乎是向后的。我猜这里......我认为会有很多评估和同一员工的一些评估。图片将其设置为列。另一方面,行似乎是静态的。使用这种策略,每个评估都会有一个列,可能会有很多。我将其切换为列,即每个区域的分数,行是员工的“评估”。我希望我不会错过这里的内容,例如根据所选的工作类型,有不同的评分标准。
以上是以下代码中的表格。您可能需要调整表格以满足您的需求。顶部DataTable
Evaluation
显示所有员工。右侧的按钮将此列表过滤为“仅限管理员”,“所有员工”以及将此数据“保存”到文件的按钮。如果需要,您可以在此处更新数据库。
下面是包含所有当前评估的public static DataTable GetEvaluationsDTStructure() {
DataTable dt = new DataTable("Evaluations");
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Employee Evaluated", typeof(string));
dt.Columns.Add("Evaluating Manager", typeof(string));
dt.Columns.Add("Job Title", typeof(string));
dt.Columns.Add("Start Date", typeof(DateTime));
dt.Columns.Add("End Date", typeof(DateTime));
dt.Columns.Add("Personal Score", typeof(double));
dt.Columns.Add("Impact Score", typeof(double));
dt.Columns.Add("Communication Score", typeof(double));
dt.Columns.Add("Decision Making Score", typeof(double));
dt.Columns.Add("Knowledge Skills Score", typeof(double));
dt.Columns.Add("Career Development Score", typeof(double));
dt.Columns.Add("Interpersonal Score", typeof(double));
return dt;
}
DataGridView
。如果有许多评估,您可能希望过滤行或搜索特定的员工,经理或工作。这就是组合框在datagridview下面的作用。组合框中添加了一个额外的空白项目以清除任何过滤器,或者用户可以单击“清除过滤器”按钮。在这里,您可以筛选所选员工的评估,并评估经理和工作。
您可以更改当前项目并添加新评估。最后,右侧有一个按钮可保存任何更改。同样,我只是将数据表写入文件。您将更新您的数据库。
注意添加新评估。
当允许用户输入数据时,必须检查有效数据。例如,分数的dgvEmployees
列设置为DataGridView
的类型。如果用户输入字符,除非您解决此问题,否则代码将崩溃。这同样适用于日期列。为了以一种简单的方式解决这个问题(不是最好的),dgvEvaluations
事件被连线以在发生这种情况时捕获,然后只是向用户显示输入无效的消息并取消网格中的任何更改。这可以防止在输入分数或日期时用户输入错误。
其他用户输入问题是用户键入新评估的员工姓名。如果用户没有准确输入名称,则稍后会出现问题。如果有新员工,则需要先将该员工添加到员工的数据库中。同样的事情将适用于“职务”,如果用户输入的内容不是现有职位,那么您以后会遇到错误。由于这些是员工和工作......也许,这里的ComboBox单元可以使用户更容易选择员工以及评估经理和工作。这样,您可以避免用户输入错误的信息。您可以在这些“员工”列中查找DataTable
。这个组合框单元格的帖子末尾有评论代码。对于有日期的单元格,有一篇很好的文章介绍了如何使double
列运行良好,用户友好并几乎保证用户输入有效日期。 How to: Host Controls in Windows Forms DataGridView Cells
话虽如此,下面的代码存在许多问题,例如,如果您将新员工添加到顶部网格然后保存数据...下面的组合框将不会更新。这是你必须解决的问题。另一个考虑因素是如果用户想要添加新评估该怎么做。使用DataError
允许用户执行此操作很方便,但是您必须实现多个事件并通过DataGridViewComboBoxColumn
进行检查。恕我直言,可以更容易地简单地添加一个按钮来“添加”新的评估,并使用此按钮打开评估表单,用户可以在其中添加分数,更改员工等...然后保存评估。这可能会使事情变得更容易,并且用户友好。
我希望这有帮助,如果我完全遗漏了某些东西......请告诉我,我会删除答案。祝你好运
DataTable定义 - 上面定义的evaluationationsDT
DateTimePicker
DataGridView
DataGridView
经理dataTable是相同的结构
jobsCBDT
主要表格方法
private static DataTable GetJobsDTStruc() {
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Job Title", typeof(string));
dt.Columns.Add("Job Description", typeof(string));
return dt;
}
希望这有帮助!
答案 1 :(得分:0)
非常感谢亲爱的JohnG提供完整的指导和答案,以下是我最后根据之前的描述显示数据的方法。我将尽快分享我的解决方案,以便尽快插入数据。
namespace Scoring_Form
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
DataClasses1DataContext db = new DataClasses1DataContext();
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.DataSource = db.Jobs.ToList();
comboBox1.DisplayMember = "JobTitle";
comboBox1.ValueMember = "JobId";
}
public DataTable subcrt(int JobId)
{
var row = from crt in db.SubCrts
join job in db.Jobs
on crt.JobId equals job.JobId
where job.JobId == JobId
select crt;
MessageBox.Show(row.Count().ToString());
return (DataTable)row;
}
private void button2_Click(object sender, EventArgs e)
{
var querySubCrts = from crt in db.SubCrts
where crt.JobId == (int)comboBox1.SelectedValue
select crt;
//--------- Add Personal Name in Header
var queryPersonal = from rwPr in db.Prs
select rwPr;
dataGridView1.ColumnCount = queryPersonal.Count() + 1;
int j = 0;
foreach (var rwPrs in queryPersonal)
{
j++;
dataGridView1.Columns[j].HeaderText = rwPrs.FName + " " + rwPrs.LName;
dataGridView1.RowCount = querySubCrts.Count() + 1;
int i = -1;
foreach (var crt in querySubCrts)
{
i++;
dataGridView1.Rows[i].Cells[0].Value = crt.Title;
//-------------
var queryScoring = from rwScoring in db.Scorings
where (rwScoring.SubCId == crt.SubCId) && (rwScoring.PrsId == rwPrs.PrsId)
select rwScoring;
foreach (var rwScoring in queryScoring)
{
dataGridView1.Rows[i].Cells[j].Value = rwScoring.Score;
}
}
}
}