Continued development
This commit is contained in:
parent
289657a7d5
commit
691a999bae
|
|
@ -225,44 +225,6 @@ namespace trakker.Data
|
|||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Executes arbitrary, ad-hoc SQL against the database inside a transaction.
|
||||
/// </summary>
|
||||
/// <param name="sql">A SQL statement to execute. The caller is responsible for
|
||||
/// ensuring the SQL is safe and properly parameterized to avoid SQL injection.</param>
|
||||
/// <remarks>
|
||||
/// This method is intended for one-off maintenance or administrative commands.
|
||||
/// It does not return any result; if a scalar value is produced by the SQL,
|
||||
/// the current implementation captures it but does not expose it to the caller.
|
||||
/// </remarks>
|
||||
public void Adhoc(string sql)
|
||||
{
|
||||
using var conn = OpenConnection();
|
||||
using var tx = conn.BeginTransaction();
|
||||
|
||||
int? result = 0;
|
||||
try
|
||||
{
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = tx;
|
||||
cmd.CommandText = sql;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
using var idCmd = conn.CreateCommand();
|
||||
idCmd.Transaction = tx;
|
||||
result = (int?)idCmd.ExecuteScalar() ;
|
||||
|
||||
tx.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
tx.Rollback();
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,5 +25,44 @@ namespace trakker.Data
|
|||
conn.Open();
|
||||
return conn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes arbitrary, ad-hoc SQL against the database inside a transaction.
|
||||
/// </summary>
|
||||
/// <param name="sql">A SQL statement to execute. The caller is responsible for
|
||||
/// ensuring the SQL is safe and properly parameterized to avoid SQL injection.</param>
|
||||
/// <remarks>
|
||||
/// This method is intended for one-off maintenance or administrative commands.
|
||||
/// It does not return any result; if a scalar value is produced by the SQL,
|
||||
/// the current implementation captures it but does not expose it to the caller.
|
||||
/// </remarks>
|
||||
public void Adhoc(string sql)
|
||||
{
|
||||
using var conn = OpenConnection();
|
||||
using var tx = conn.BeginTransaction();
|
||||
|
||||
int? result = 0;
|
||||
try
|
||||
{
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = tx;
|
||||
cmd.CommandText = sql;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
using var idCmd = conn.CreateCommand();
|
||||
idCmd.Transaction = tx;
|
||||
result = (int?)idCmd.ExecuteScalar() ;
|
||||
|
||||
tx.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
tx.Rollback();
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
using System.ComponentModel;
|
||||
using trakker.Models;
|
||||
|
||||
namespace trakker.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides data access methods for the <see cref="Models.Project"/> entity.
|
||||
/// This class encapsulates database operations such as upsert, delete and ad-hoc
|
||||
/// SQL execution for projects. It inherits from <see cref="DataAccess"/> which
|
||||
/// provides connection management.
|
||||
/// </summary>
|
||||
internal class ProjectData(string connectionString) : DataAccess(connectionString)
|
||||
{
|
||||
public BindingList<Project> Get(string? projectId = null)
|
||||
{
|
||||
var results = new BindingList<Project>();
|
||||
|
||||
string whereClause = "1 = 1";
|
||||
if (projectId != null)
|
||||
{
|
||||
whereClause = "p.project_id = $project_id";
|
||||
}
|
||||
|
||||
string sql = $@"
|
||||
SELECT
|
||||
p.project_id,
|
||||
p.client_id,
|
||||
p.project_code,
|
||||
c.name AS client_name,
|
||||
p.name AS project_name,
|
||||
p.description,
|
||||
p.start_date,
|
||||
p.end_date,
|
||||
p.budget,
|
||||
p.status,
|
||||
p.hourly_rate,
|
||||
p.notes,
|
||||
p.created_at,
|
||||
p.updated_at
|
||||
FROM projects p
|
||||
LEFT JOIN clients c ON p.client_id = c.client_id
|
||||
WHERE p.status = 'active'
|
||||
AND {whereClause}
|
||||
ORDER BY p.start_date DESC, p.name ASC;
|
||||
;
|
||||
";
|
||||
|
||||
using var conn = OpenConnection();
|
||||
using var cmd = conn.CreateCommand();
|
||||
cmd.CommandText = sql;
|
||||
|
||||
if (projectId != null)
|
||||
{
|
||||
cmd.Parameters.AddWithValue("$project_id", projectId);
|
||||
}
|
||||
using var reader = cmd.ExecuteReader();
|
||||
|
||||
var _var1 = reader.GetOrdinal("project_id");
|
||||
var _var2 = reader.GetOrdinal("client_id");
|
||||
var _var3 = reader.GetOrdinal("project_code");
|
||||
var _var4 = reader.GetOrdinal("client_name");
|
||||
var _var5 = reader.GetOrdinal("project_name");
|
||||
var _var6 = reader.GetOrdinal("description");
|
||||
var _var7 = reader.GetOrdinal("start_date");
|
||||
var _var8 = reader.GetOrdinal("end_date");
|
||||
var _var9 = reader.GetOrdinal("budget");
|
||||
var _var10 = reader.GetOrdinal("status");
|
||||
var _var11 = reader.GetOrdinal("hourly_rate");
|
||||
var _var12 = reader.GetOrdinal("notes");
|
||||
var _var13 = reader.GetOrdinal("created_at");
|
||||
var _var14 = reader.GetOrdinal("updated_at");
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
results.Add(new Project
|
||||
{
|
||||
ProjectId = reader.GetString(_var1),
|
||||
ClientId = reader.GetString(_var2),
|
||||
ProjectCode = reader.GetString(_var3),
|
||||
ClientName = reader.GetString(_var4),
|
||||
ProjectName = reader.GetString(_var5),
|
||||
Description = reader.GetString(_var6),
|
||||
StartDate = reader.IsDBNull(_var7) ? null : reader.GetDateTime(_var7),
|
||||
EndDate = reader.IsDBNull(_var8) ? null : reader.GetDateTime(_var8),
|
||||
Budget = reader.GetDecimal(_var9),
|
||||
Status = reader.GetString(_var10),
|
||||
HourlyRate = reader.GetDecimal(_var11),
|
||||
Notes = reader.GetString(_var12),
|
||||
CreatedAt = reader.GetDateTime(_var13),
|
||||
UpdatedAt = reader.GetDateTime(_var14),
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new project record or updates an existing one (upsert) using
|
||||
/// the provided <paramref name="project"/> model. This method executes
|
||||
/// a single SQL statement inside a transaction and will commit on
|
||||
/// success or roll back on failure.
|
||||
/// </summary>
|
||||
/// <param name="project">The <see cref="Client"/> model to insert or update. Must not be null.</param>
|
||||
/// <remarks>
|
||||
/// The SQL statement uses an ON CONFLICT clause to perform the update when a
|
||||
/// matching <c>project_id</c> already exists. Parameter names correspond to the
|
||||
/// project model property names.
|
||||
/// </remarks>
|
||||
public void Upsert(Project project)
|
||||
{
|
||||
const string sql = @"
|
||||
INSERT INTO projects (
|
||||
project_id,
|
||||
client_id,
|
||||
name,
|
||||
description,
|
||||
start_date,
|
||||
end_date,
|
||||
budget,
|
||||
status,
|
||||
hourly_rate,
|
||||
notes
|
||||
)
|
||||
VALUES (
|
||||
$project_id,
|
||||
$client_id,
|
||||
$name,
|
||||
$description,
|
||||
$start_date,
|
||||
$end_date,
|
||||
$budget,
|
||||
$status,
|
||||
$hourly_rate,
|
||||
$notes
|
||||
)
|
||||
ON CONFLICT (project_id) DO UPDATE SET
|
||||
client_id = excluded.client_id,
|
||||
name = excluded.name,
|
||||
description = excluded.description,
|
||||
start_date = excluded.start_date,
|
||||
end_date = excluded.end_date,
|
||||
budget = excluded.budget,
|
||||
status = excluded.status,
|
||||
hourly_rate = excluded.hourly_rate,
|
||||
notes = excluded.notes,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
";
|
||||
|
||||
using var conn = OpenConnection();
|
||||
using var tx = conn.BeginTransaction();
|
||||
|
||||
try
|
||||
{
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = tx;
|
||||
cmd.CommandText = sql;
|
||||
cmd.Parameters.AddWithValue("$project_id", project.ProjectId);
|
||||
cmd.Parameters.AddWithValue("$client_id", project.ClientId);
|
||||
cmd.Parameters.AddWithValue("$name", project.ProjectName);
|
||||
cmd.Parameters.AddWithValue("$description", project.Description);
|
||||
cmd.Parameters.AddWithValue("$start_date", project.StartDate);
|
||||
cmd.Parameters.AddWithValue("$end_date", project.EndDate);
|
||||
cmd.Parameters.AddWithValue("$budget", project.Budget);
|
||||
cmd.Parameters.AddWithValue("$status", project.Status);
|
||||
cmd.Parameters.AddWithValue("$hourly_rate", project.HourlyRate);
|
||||
cmd.Parameters.AddWithValue("$notes", project.Notes);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
tx.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
tx.Rollback();
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Deletes the project with the specified <paramref name="projectId"/> from the
|
||||
/// database.
|
||||
/// </summary>
|
||||
/// <param name="projectId">The identifier of the project to delete.</param>
|
||||
/// <returns>An optional integer representing any scalar value returned by the
|
||||
/// command executed after deletion (if applicable). May be null.</returns>
|
||||
/// <remarks>
|
||||
/// The method executes within a transaction. The current implementation attempts
|
||||
/// to read a scalar value after the delete; that value depends on surrounding
|
||||
/// database triggers or commands and may be null.
|
||||
/// </remarks>
|
||||
public int? Delete(string projectId)
|
||||
{
|
||||
const string sql = @"
|
||||
DELETE FROM
|
||||
projects
|
||||
WHERE
|
||||
project_id = $project_id
|
||||
;
|
||||
";
|
||||
|
||||
using var conn = OpenConnection();
|
||||
using var tx = conn.BeginTransaction();
|
||||
|
||||
int? result = 0;
|
||||
try
|
||||
{
|
||||
using (var cmd = conn.CreateCommand())
|
||||
{
|
||||
cmd.Transaction = tx;
|
||||
cmd.CommandText = sql;
|
||||
cmd.Parameters.AddWithValue("$project_id", projectId);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
using var idCmd = conn.CreateCommand();
|
||||
idCmd.Transaction = tx;
|
||||
result = (int?)idCmd.ExecuteScalar() ;
|
||||
|
||||
tx.Commit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
tx.Rollback();
|
||||
throw;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -34,16 +34,20 @@
|
|||
MainForm_StatusStrip = new StatusStrip();
|
||||
tabControlMainForm = new TabControl();
|
||||
MainForm_TabPage1 = new TabPage();
|
||||
button1 = new Button();
|
||||
MainForm_TabPage2 = new TabPage();
|
||||
tableLayoutPanel1Tab2 = new TableLayoutPanel();
|
||||
tableLayoutPanelClients1 = new TableLayoutPanel();
|
||||
dataGridViewClients = new DataGridView();
|
||||
MainForm_TabPage3 = new TabPage();
|
||||
tableLayoutPanelProjects1 = new TableLayoutPanel();
|
||||
dataGridViewProjects = new DataGridView();
|
||||
MainForm_MenuStrip.SuspendLayout();
|
||||
tabControlMainForm.SuspendLayout();
|
||||
MainForm_TabPage1.SuspendLayout();
|
||||
MainForm_TabPage2.SuspendLayout();
|
||||
tableLayoutPanel1Tab2.SuspendLayout();
|
||||
tableLayoutPanelClients1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dataGridViewClients).BeginInit();
|
||||
MainForm_TabPage3.SuspendLayout();
|
||||
tableLayoutPanelProjects1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)dataGridViewProjects).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// MainForm_MenuStrip
|
||||
|
|
@ -52,7 +56,7 @@
|
|||
MainForm_MenuStrip.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem });
|
||||
MainForm_MenuStrip.Location = new Point(0, 0);
|
||||
MainForm_MenuStrip.Name = "MainForm_MenuStrip";
|
||||
MainForm_MenuStrip.Size = new Size(1343, 40);
|
||||
MainForm_MenuStrip.Size = new Size(1878, 40);
|
||||
MainForm_MenuStrip.TabIndex = 0;
|
||||
MainForm_MenuStrip.Text = "menuStrip1";
|
||||
//
|
||||
|
|
@ -73,9 +77,9 @@
|
|||
// MainForm_StatusStrip
|
||||
//
|
||||
MainForm_StatusStrip.ImageScalingSize = new Size(32, 32);
|
||||
MainForm_StatusStrip.Location = new Point(0, 983);
|
||||
MainForm_StatusStrip.Location = new Point(0, 1060);
|
||||
MainForm_StatusStrip.Name = "MainForm_StatusStrip";
|
||||
MainForm_StatusStrip.Size = new Size(1343, 22);
|
||||
MainForm_StatusStrip.Size = new Size(1878, 22);
|
||||
MainForm_StatusStrip.TabIndex = 1;
|
||||
MainForm_StatusStrip.Text = "MainForm_StatusStrip";
|
||||
//
|
||||
|
|
@ -83,37 +87,27 @@
|
|||
//
|
||||
tabControlMainForm.Controls.Add(MainForm_TabPage1);
|
||||
tabControlMainForm.Controls.Add(MainForm_TabPage2);
|
||||
tabControlMainForm.Controls.Add(MainForm_TabPage3);
|
||||
tabControlMainForm.Dock = DockStyle.Fill;
|
||||
tabControlMainForm.Location = new Point(0, 40);
|
||||
tabControlMainForm.Name = "tabControlMainForm";
|
||||
tabControlMainForm.SelectedIndex = 0;
|
||||
tabControlMainForm.Size = new Size(1343, 943);
|
||||
tabControlMainForm.Size = new Size(1878, 1020);
|
||||
tabControlMainForm.TabIndex = 2;
|
||||
//
|
||||
// MainForm_TabPage1
|
||||
//
|
||||
MainForm_TabPage1.Controls.Add(button1);
|
||||
MainForm_TabPage1.Location = new Point(8, 46);
|
||||
MainForm_TabPage1.Name = "MainForm_TabPage1";
|
||||
MainForm_TabPage1.Padding = new Padding(3);
|
||||
MainForm_TabPage1.Size = new Size(1327, 889);
|
||||
MainForm_TabPage1.Size = new Size(1862, 966);
|
||||
MainForm_TabPage1.TabIndex = 0;
|
||||
MainForm_TabPage1.Text = "Tab 1";
|
||||
MainForm_TabPage1.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// button1
|
||||
//
|
||||
button1.Location = new Point(39, 47);
|
||||
button1.Name = "button1";
|
||||
button1.Size = new Size(150, 46);
|
||||
button1.TabIndex = 0;
|
||||
button1.Text = "button1";
|
||||
button1.UseVisualStyleBackColor = true;
|
||||
button1.Click += button1_Click;
|
||||
//
|
||||
// MainForm_TabPage2
|
||||
//
|
||||
MainForm_TabPage2.Controls.Add(tableLayoutPanel1Tab2);
|
||||
MainForm_TabPage2.Controls.Add(tableLayoutPanelClients1);
|
||||
MainForm_TabPage2.Location = new Point(8, 46);
|
||||
MainForm_TabPage2.Name = "MainForm_TabPage2";
|
||||
MainForm_TabPage2.Padding = new Padding(3);
|
||||
|
|
@ -122,20 +116,20 @@
|
|||
MainForm_TabPage2.Text = "Tab 2";
|
||||
MainForm_TabPage2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tableLayoutPanel1Tab2
|
||||
// tableLayoutPanelClients1
|
||||
//
|
||||
tableLayoutPanel1Tab2.ColumnCount = 1;
|
||||
tableLayoutPanel1Tab2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1Tab2.Controls.Add(dataGridViewClients, 0, 1);
|
||||
tableLayoutPanel1Tab2.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel1Tab2.Location = new Point(3, 3);
|
||||
tableLayoutPanel1Tab2.Name = "tableLayoutPanel1Tab2";
|
||||
tableLayoutPanel1Tab2.RowCount = 3;
|
||||
tableLayoutPanel1Tab2.RowStyles.Add(new RowStyle(SizeType.Absolute, 1F));
|
||||
tableLayoutPanel1Tab2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1Tab2.RowStyles.Add(new RowStyle(SizeType.Absolute, 200F));
|
||||
tableLayoutPanel1Tab2.Size = new Size(1321, 883);
|
||||
tableLayoutPanel1Tab2.TabIndex = 0;
|
||||
tableLayoutPanelClients1.ColumnCount = 1;
|
||||
tableLayoutPanelClients1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanelClients1.Controls.Add(dataGridViewClients, 0, 1);
|
||||
tableLayoutPanelClients1.Dock = DockStyle.Fill;
|
||||
tableLayoutPanelClients1.Location = new Point(3, 3);
|
||||
tableLayoutPanelClients1.Name = "tableLayoutPanelClients1";
|
||||
tableLayoutPanelClients1.RowCount = 3;
|
||||
tableLayoutPanelClients1.RowStyles.Add(new RowStyle(SizeType.Absolute, 1F));
|
||||
tableLayoutPanelClients1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanelClients1.RowStyles.Add(new RowStyle(SizeType.Absolute, 200F));
|
||||
tableLayoutPanelClients1.Size = new Size(1321, 883);
|
||||
tableLayoutPanelClients1.TabIndex = 0;
|
||||
//
|
||||
// dataGridViewClients
|
||||
//
|
||||
|
|
@ -150,11 +144,49 @@
|
|||
dataGridViewClients.Size = new Size(1315, 676);
|
||||
dataGridViewClients.TabIndex = 0;
|
||||
//
|
||||
// MainForm_TabPage3
|
||||
//
|
||||
MainForm_TabPage3.Controls.Add(tableLayoutPanelProjects1);
|
||||
MainForm_TabPage3.Location = new Point(8, 46);
|
||||
MainForm_TabPage3.Name = "MainForm_TabPage3";
|
||||
MainForm_TabPage3.Size = new Size(1327, 889);
|
||||
MainForm_TabPage3.TabIndex = 2;
|
||||
MainForm_TabPage3.Text = "Tab 3";
|
||||
MainForm_TabPage3.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tableLayoutPanelProjects1
|
||||
//
|
||||
tableLayoutPanelProjects1.ColumnCount = 1;
|
||||
tableLayoutPanelProjects1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanelProjects1.Controls.Add(dataGridViewProjects, 0, 1);
|
||||
tableLayoutPanelProjects1.Dock = DockStyle.Fill;
|
||||
tableLayoutPanelProjects1.Location = new Point(0, 0);
|
||||
tableLayoutPanelProjects1.Name = "tableLayoutPanelProjects1";
|
||||
tableLayoutPanelProjects1.RowCount = 3;
|
||||
tableLayoutPanelProjects1.RowStyles.Add(new RowStyle(SizeType.Absolute, 1F));
|
||||
tableLayoutPanelProjects1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanelProjects1.RowStyles.Add(new RowStyle(SizeType.Absolute, 200F));
|
||||
tableLayoutPanelProjects1.Size = new Size(1327, 889);
|
||||
tableLayoutPanelProjects1.TabIndex = 1;
|
||||
//
|
||||
// dataGridViewProjects
|
||||
//
|
||||
dataGridViewProjects.AllowUserToAddRows = false;
|
||||
dataGridViewProjects.AllowUserToDeleteRows = false;
|
||||
dataGridViewProjects.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
dataGridViewProjects.Dock = DockStyle.Fill;
|
||||
dataGridViewProjects.Location = new Point(3, 4);
|
||||
dataGridViewProjects.Name = "dataGridViewProjects";
|
||||
dataGridViewProjects.ReadOnly = true;
|
||||
dataGridViewProjects.RowHeadersWidth = 82;
|
||||
dataGridViewProjects.Size = new Size(1321, 682);
|
||||
dataGridViewProjects.TabIndex = 0;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(13F, 32F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1343, 1005);
|
||||
ClientSize = new Size(1878, 1082);
|
||||
Controls.Add(tabControlMainForm);
|
||||
Controls.Add(MainForm_StatusStrip);
|
||||
Controls.Add(MainForm_MenuStrip);
|
||||
|
|
@ -164,10 +196,12 @@
|
|||
MainForm_MenuStrip.ResumeLayout(false);
|
||||
MainForm_MenuStrip.PerformLayout();
|
||||
tabControlMainForm.ResumeLayout(false);
|
||||
MainForm_TabPage1.ResumeLayout(false);
|
||||
MainForm_TabPage2.ResumeLayout(false);
|
||||
tableLayoutPanel1Tab2.ResumeLayout(false);
|
||||
tableLayoutPanelClients1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dataGridViewClients).EndInit();
|
||||
MainForm_TabPage3.ResumeLayout(false);
|
||||
tableLayoutPanelProjects1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)dataGridViewProjects).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
|
@ -181,8 +215,10 @@
|
|||
private TabPage MainForm_TabPage2;
|
||||
private ToolStripMenuItem fileToolStripMenuItem;
|
||||
private ToolStripMenuItem MainForm_Exit_MenuItem;
|
||||
private Button button1;
|
||||
private TableLayoutPanel tableLayoutPanel1Tab2;
|
||||
private TableLayoutPanel tableLayoutPanelClients1;
|
||||
private DataGridView dataGridViewClients;
|
||||
private TabPage MainForm_TabPage3;
|
||||
private TableLayoutPanel tableLayoutPanelProjects1;
|
||||
private DataGridView dataGridViewProjects;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ namespace trakker
|
|||
|
||||
tabControlMainForm.TabPages[0].Text = " Home ";
|
||||
tabControlMainForm.TabPages[1].Text = " Clients ";
|
||||
tabControlMainForm.TabPages[2].Text = " Projects ";
|
||||
|
||||
_ctrl = new Services.MainCtrl(this, connectionString);
|
||||
}
|
||||
|
|
@ -58,11 +59,11 @@ namespace trakker
|
|||
dataGridViewClients.AutoGenerateColumns = false;
|
||||
dataGridViewClients.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||
dataGridViewClients.BackgroundColor = Color.White;
|
||||
dataGridViewClients.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dataGridViewClients.RowHeadersVisible = false;
|
||||
dataGridViewClients.ColumnHeadersVisible = true;
|
||||
dataGridViewClients.MultiSelect = false;
|
||||
dataGridViewClients.DataSource = clients;
|
||||
dataGridViewClients.MultiSelect = false;
|
||||
dataGridViewClients.RowHeadersVisible = false;
|
||||
dataGridViewClients.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
|
||||
dataGridViewClients.Columns.Clear();
|
||||
{
|
||||
|
|
@ -146,23 +147,160 @@ namespace trakker
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
public void FillDataGridViewProjects(BindingSource projects)
|
||||
{
|
||||
var dialog = new ClientForm(new Client());
|
||||
dataGridViewProjects.DataSource = projects;
|
||||
}
|
||||
public void InitDataGridViewProjects()
|
||||
{
|
||||
dataGridViewProjects.AllowUserToAddRows = true;
|
||||
dataGridViewProjects.AllowUserToDeleteRows = true;
|
||||
dataGridViewProjects.AutoGenerateColumns = false;
|
||||
dataGridViewProjects.BackgroundColor = Color.White;
|
||||
dataGridViewProjects.ColumnHeadersVisible = true;
|
||||
dataGridViewProjects.MultiSelect = false;
|
||||
dataGridViewProjects.RowHeadersVisible = false;
|
||||
dataGridViewProjects.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
|
||||
dataGridViewProjects.Columns.Clear();
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.None,
|
||||
DataPropertyName = "ProjectName",
|
||||
Name = "Project Name",
|
||||
Visible = true,
|
||||
Width = 350,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "ClientName",
|
||||
Name = "Client Name",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "StartDate",
|
||||
DefaultCellStyle = { Format = "MM/dd/yyyy" },
|
||||
Name = "Start Date",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "EndDate",
|
||||
DefaultCellStyle = { Format = "MM/dd/yyyy" },
|
||||
Name = "End Date",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "HourlyRate",
|
||||
Name = "Hourly Rate",
|
||||
Visible = true,
|
||||
};
|
||||
textColumn.DefaultCellStyle.Format = "$#,##0.00";
|
||||
textColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
|
||||
textColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight;
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Budget",
|
||||
Name = "Budget",
|
||||
Visible = true,
|
||||
};
|
||||
textColumn.DefaultCellStyle.Format = "$#,##0.00";
|
||||
textColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
|
||||
textColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight;
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Status",
|
||||
Name = "Status",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
|
||||
dataGridViewProjects.DoubleClick += (s, e) =>
|
||||
{
|
||||
if (dataGridViewProjects.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedProject = dataGridViewProjects.SelectedRows[0].DataBoundItem as Project;
|
||||
if (selectedProject != null)
|
||||
{
|
||||
var dialog = new ProjectForm(selectedProject, _ctrl.GetClients());
|
||||
if (dialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
Client client = dialog.Client;
|
||||
ClientData clientData = new ClientData(connectionString);
|
||||
Project project = dialog.Project;
|
||||
ProjectData projectData = new ProjectData(connectionString);
|
||||
try
|
||||
{
|
||||
clientData.Upsert(client);
|
||||
projectData.Upsert(project);
|
||||
_ctrl.LoadProjects(); // Reload projects to update the DataGridView with any changes
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error saving client: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
MessageBox.Show($"Error saving project: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dataGridViewClients.SelectionChanged += (s, e) =>
|
||||
{
|
||||
if (dataGridViewClients.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedClient = dataGridViewClients.SelectedRows[0].DataBoundItem as Client;
|
||||
if (selectedClient != null)
|
||||
{
|
||||
// Handle the selected client as needed
|
||||
// MessageBox.Show($"Selected Client: {selectedClient.AddressStreet}", "Client Selected", MessageBoxButtons.OK, MessageBoxIcon.Information );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//private void button1_Click(object sender, EventArgs e)
|
||||
//{
|
||||
// var dialog = new ClientForm(new Client());
|
||||
// if (dialog.ShowDialog(this) == DialogResult.OK)
|
||||
// {
|
||||
// Client client = dialog.Client;
|
||||
// ClientData clientData = new ClientData(connectionString);
|
||||
// try
|
||||
// {
|
||||
// clientData.Upsert(client);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// MessageBox.Show($"Error saving client: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,435 @@
|
|||
namespace trakker.Forms
|
||||
{
|
||||
partial class ProjectForm
|
||||
{
|
||||
/// <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()
|
||||
{
|
||||
groupBoxNewClient = new GroupBox();
|
||||
tableLayoutPanel1 = new TableLayoutPanel();
|
||||
tableLayoutPanel2 = new TableLayoutPanel();
|
||||
labelClient = new Label();
|
||||
labelName = new Label();
|
||||
labelDescription = new Label();
|
||||
labelStartDate = new Label();
|
||||
labelHourlyRate = new Label();
|
||||
textBoxName = new TextBox();
|
||||
comboBoxClient = new ComboBox();
|
||||
tableLayoutPanel6 = new TableLayoutPanel();
|
||||
dateTimePickerStartDate = new DateTimePicker();
|
||||
dateTimePickerEndDate = new DateTimePicker();
|
||||
labelEndDate = new Label();
|
||||
richTextBoxDescription = new RichTextBox();
|
||||
tableLayoutPanel4 = new TableLayoutPanel();
|
||||
labelBudget = new Label();
|
||||
labelStatus = new Label();
|
||||
comboBoxStatus = new ComboBox();
|
||||
textBoxHourlyRate = new TextBox();
|
||||
textBoxBudget = new TextBox();
|
||||
groupBoxNotes = new GroupBox();
|
||||
richTextBoxNotes = new RichTextBox();
|
||||
tableLayoutPanel3 = new TableLayoutPanel();
|
||||
buttonOkay = new Button();
|
||||
buttonCancel = new Button();
|
||||
labelCreatedUpdatedDT = new Label();
|
||||
groupBoxNewClient.SuspendLayout();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
tableLayoutPanel2.SuspendLayout();
|
||||
tableLayoutPanel6.SuspendLayout();
|
||||
tableLayoutPanel4.SuspendLayout();
|
||||
groupBoxNotes.SuspendLayout();
|
||||
tableLayoutPanel3.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// groupBoxNewClient
|
||||
//
|
||||
groupBoxNewClient.Controls.Add(tableLayoutPanel1);
|
||||
groupBoxNewClient.Dock = DockStyle.Fill;
|
||||
groupBoxNewClient.Location = new Point(0, 0);
|
||||
groupBoxNewClient.Name = "groupBoxNewClient";
|
||||
groupBoxNewClient.Size = new Size(1144, 660);
|
||||
groupBoxNewClient.TabIndex = 1;
|
||||
groupBoxNewClient.TabStop = false;
|
||||
groupBoxNewClient.Text = "New Client";
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
tableLayoutPanel1.ColumnCount = 1;
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(groupBoxNotes, 0, 1);
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel3, 0, 2);
|
||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel1.Location = new Point(3, 35);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 3;
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 242F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 75F));
|
||||
tableLayoutPanel1.Size = new Size(1138, 622);
|
||||
tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
tableLayoutPanel2.ColumnCount = 2;
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 150F));
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel2.Controls.Add(labelClient, 0, 0);
|
||||
tableLayoutPanel2.Controls.Add(labelName, 0, 1);
|
||||
tableLayoutPanel2.Controls.Add(labelDescription, 0, 2);
|
||||
tableLayoutPanel2.Controls.Add(labelStartDate, 0, 3);
|
||||
tableLayoutPanel2.Controls.Add(labelHourlyRate, 0, 4);
|
||||
tableLayoutPanel2.Controls.Add(textBoxName, 1, 1);
|
||||
tableLayoutPanel2.Controls.Add(comboBoxClient, 1, 0);
|
||||
tableLayoutPanel2.Controls.Add(tableLayoutPanel6, 1, 3);
|
||||
tableLayoutPanel2.Controls.Add(richTextBoxDescription, 1, 2);
|
||||
tableLayoutPanel2.Controls.Add(tableLayoutPanel4, 1, 4);
|
||||
tableLayoutPanel2.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel2.Location = new Point(3, 3);
|
||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
tableLayoutPanel2.RowCount = 5;
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 100F));
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
|
||||
tableLayoutPanel2.Size = new Size(1132, 299);
|
||||
tableLayoutPanel2.TabIndex = 1;
|
||||
//
|
||||
// labelClient
|
||||
//
|
||||
labelClient.AutoSize = true;
|
||||
labelClient.Dock = DockStyle.Fill;
|
||||
labelClient.Location = new Point(3, 0);
|
||||
labelClient.Name = "labelClient";
|
||||
labelClient.Size = new Size(144, 50);
|
||||
labelClient.TabIndex = 0;
|
||||
labelClient.Text = "Client *";
|
||||
//
|
||||
// labelName
|
||||
//
|
||||
labelName.AutoSize = true;
|
||||
labelName.Dock = DockStyle.Fill;
|
||||
labelName.Location = new Point(3, 50);
|
||||
labelName.Name = "labelName";
|
||||
labelName.Size = new Size(144, 50);
|
||||
labelName.TabIndex = 0;
|
||||
labelName.Text = "Name *";
|
||||
//
|
||||
// labelDescription
|
||||
//
|
||||
labelDescription.AutoSize = true;
|
||||
labelDescription.Dock = DockStyle.Fill;
|
||||
labelDescription.Location = new Point(3, 100);
|
||||
labelDescription.Name = "labelDescription";
|
||||
labelDescription.Size = new Size(144, 100);
|
||||
labelDescription.TabIndex = 0;
|
||||
labelDescription.Text = "Description";
|
||||
//
|
||||
// labelStartDate
|
||||
//
|
||||
labelStartDate.AutoSize = true;
|
||||
labelStartDate.Dock = DockStyle.Fill;
|
||||
labelStartDate.Location = new Point(3, 200);
|
||||
labelStartDate.Name = "labelStartDate";
|
||||
labelStartDate.Size = new Size(144, 50);
|
||||
labelStartDate.TabIndex = 0;
|
||||
labelStartDate.Text = "Start Date";
|
||||
//
|
||||
// labelHourlyRate
|
||||
//
|
||||
labelHourlyRate.AutoSize = true;
|
||||
labelHourlyRate.Dock = DockStyle.Fill;
|
||||
labelHourlyRate.Location = new Point(3, 250);
|
||||
labelHourlyRate.Name = "labelHourlyRate";
|
||||
labelHourlyRate.Size = new Size(144, 50);
|
||||
labelHourlyRate.TabIndex = 0;
|
||||
labelHourlyRate.Text = "Hourly Rate";
|
||||
//
|
||||
// textBoxName
|
||||
//
|
||||
textBoxName.Dock = DockStyle.Left;
|
||||
textBoxName.Location = new Point(153, 53);
|
||||
textBoxName.Name = "textBoxName";
|
||||
textBoxName.PlaceholderText = "Project X";
|
||||
textBoxName.Size = new Size(913, 39);
|
||||
textBoxName.TabIndex = 2;
|
||||
textBoxName.Validating += textBoxName_Validating;
|
||||
//
|
||||
// comboBoxClient
|
||||
//
|
||||
comboBoxClient.Dock = DockStyle.Fill;
|
||||
comboBoxClient.FlatStyle = FlatStyle.Flat;
|
||||
comboBoxClient.FormattingEnabled = true;
|
||||
comboBoxClient.Location = new Point(153, 3);
|
||||
comboBoxClient.Name = "comboBoxClient";
|
||||
comboBoxClient.Size = new Size(976, 40);
|
||||
comboBoxClient.TabIndex = 1;
|
||||
//
|
||||
// tableLayoutPanel6
|
||||
//
|
||||
tableLayoutPanel6.ColumnCount = 3;
|
||||
tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40F));
|
||||
tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40F));
|
||||
tableLayoutPanel6.Controls.Add(dateTimePickerStartDate, 0, 0);
|
||||
tableLayoutPanel6.Controls.Add(dateTimePickerEndDate, 2, 0);
|
||||
tableLayoutPanel6.Controls.Add(labelEndDate, 1, 0);
|
||||
tableLayoutPanel6.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel6.Location = new Point(153, 203);
|
||||
tableLayoutPanel6.Name = "tableLayoutPanel6";
|
||||
tableLayoutPanel6.RowCount = 1;
|
||||
tableLayoutPanel6.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel6.Size = new Size(976, 44);
|
||||
tableLayoutPanel6.TabIndex = 7;
|
||||
//
|
||||
// dateTimePickerStartDate
|
||||
//
|
||||
dateTimePickerStartDate.Format = DateTimePickerFormat.Short;
|
||||
dateTimePickerStartDate.Location = new Point(3, 3);
|
||||
dateTimePickerStartDate.Name = "dateTimePickerStartDate";
|
||||
dateTimePickerStartDate.Size = new Size(384, 39);
|
||||
dateTimePickerStartDate.TabIndex = 0;
|
||||
dateTimePickerStartDate.TabStop = false;
|
||||
//
|
||||
// dateTimePickerEndDate
|
||||
//
|
||||
dateTimePickerEndDate.Format = DateTimePickerFormat.Short;
|
||||
dateTimePickerEndDate.Location = new Point(588, 3);
|
||||
dateTimePickerEndDate.Name = "dateTimePickerEndDate";
|
||||
dateTimePickerEndDate.Size = new Size(385, 39);
|
||||
dateTimePickerEndDate.TabIndex = 1;
|
||||
dateTimePickerEndDate.TabStop = false;
|
||||
//
|
||||
// labelEndDate
|
||||
//
|
||||
labelEndDate.AutoSize = true;
|
||||
labelEndDate.Dock = DockStyle.Fill;
|
||||
labelEndDate.Location = new Point(393, 0);
|
||||
labelEndDate.Name = "labelEndDate";
|
||||
labelEndDate.Size = new Size(189, 44);
|
||||
labelEndDate.TabIndex = 2;
|
||||
labelEndDate.Text = "End Date";
|
||||
labelEndDate.TextAlign = ContentAlignment.TopCenter;
|
||||
//
|
||||
// richTextBoxDescription
|
||||
//
|
||||
richTextBoxDescription.Dock = DockStyle.Fill;
|
||||
richTextBoxDescription.Location = new Point(153, 103);
|
||||
richTextBoxDescription.Name = "richTextBoxDescription";
|
||||
richTextBoxDescription.Size = new Size(976, 94);
|
||||
richTextBoxDescription.TabIndex = 3;
|
||||
richTextBoxDescription.Text = "";
|
||||
//
|
||||
// tableLayoutPanel4
|
||||
//
|
||||
tableLayoutPanel4.ColumnCount = 5;
|
||||
tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel4.Controls.Add(labelBudget, 1, 0);
|
||||
tableLayoutPanel4.Controls.Add(labelStatus, 3, 0);
|
||||
tableLayoutPanel4.Controls.Add(comboBoxStatus, 4, 0);
|
||||
tableLayoutPanel4.Controls.Add(textBoxHourlyRate, 0, 0);
|
||||
tableLayoutPanel4.Controls.Add(textBoxBudget, 2, 0);
|
||||
tableLayoutPanel4.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel4.Location = new Point(153, 253);
|
||||
tableLayoutPanel4.Name = "tableLayoutPanel4";
|
||||
tableLayoutPanel4.RowCount = 1;
|
||||
tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel4.Size = new Size(976, 44);
|
||||
tableLayoutPanel4.TabIndex = 9;
|
||||
//
|
||||
// labelBudget
|
||||
//
|
||||
labelBudget.AutoSize = true;
|
||||
labelBudget.Dock = DockStyle.Fill;
|
||||
labelBudget.Location = new Point(198, 0);
|
||||
labelBudget.Name = "labelBudget";
|
||||
labelBudget.Size = new Size(189, 44);
|
||||
labelBudget.TabIndex = 0;
|
||||
labelBudget.Text = "Budget";
|
||||
labelBudget.TextAlign = ContentAlignment.TopCenter;
|
||||
//
|
||||
// labelStatus
|
||||
//
|
||||
labelStatus.AutoSize = true;
|
||||
labelStatus.Dock = DockStyle.Fill;
|
||||
labelStatus.Location = new Point(588, 0);
|
||||
labelStatus.Name = "labelStatus";
|
||||
labelStatus.Size = new Size(189, 44);
|
||||
labelStatus.TabIndex = 1;
|
||||
labelStatus.Text = "Status";
|
||||
labelStatus.TextAlign = ContentAlignment.TopCenter;
|
||||
//
|
||||
// comboBoxStatus
|
||||
//
|
||||
comboBoxStatus.FlatStyle = FlatStyle.Flat;
|
||||
comboBoxStatus.FormattingEnabled = true;
|
||||
comboBoxStatus.Location = new Point(783, 3);
|
||||
comboBoxStatus.Name = "comboBoxStatus";
|
||||
comboBoxStatus.Size = new Size(190, 40);
|
||||
comboBoxStatus.TabIndex = 6;
|
||||
//
|
||||
// textBoxHourlyRate
|
||||
//
|
||||
textBoxHourlyRate.Location = new Point(3, 3);
|
||||
textBoxHourlyRate.Name = "textBoxHourlyRate";
|
||||
textBoxHourlyRate.Size = new Size(189, 39);
|
||||
textBoxHourlyRate.TabIndex = 7;
|
||||
//
|
||||
// textBoxBudget
|
||||
//
|
||||
textBoxBudget.Location = new Point(393, 3);
|
||||
textBoxBudget.Name = "textBoxBudget";
|
||||
textBoxBudget.Size = new Size(189, 39);
|
||||
textBoxBudget.TabIndex = 8;
|
||||
//
|
||||
// groupBoxNotes
|
||||
//
|
||||
groupBoxNotes.Controls.Add(richTextBoxNotes);
|
||||
groupBoxNotes.Dock = DockStyle.Fill;
|
||||
groupBoxNotes.Location = new Point(3, 308);
|
||||
groupBoxNotes.Name = "groupBoxNotes";
|
||||
groupBoxNotes.Size = new Size(1132, 236);
|
||||
groupBoxNotes.TabIndex = 0;
|
||||
groupBoxNotes.TabStop = false;
|
||||
groupBoxNotes.Text = "Notes";
|
||||
//
|
||||
// richTextBoxNotes
|
||||
//
|
||||
richTextBoxNotes.Dock = DockStyle.Fill;
|
||||
richTextBoxNotes.Location = new Point(3, 35);
|
||||
richTextBoxNotes.Name = "richTextBoxNotes";
|
||||
richTextBoxNotes.Size = new Size(1126, 198);
|
||||
richTextBoxNotes.TabIndex = 7;
|
||||
richTextBoxNotes.Text = "";
|
||||
//
|
||||
// tableLayoutPanel3
|
||||
//
|
||||
tableLayoutPanel3.ColumnCount = 3;
|
||||
tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200F));
|
||||
tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200F));
|
||||
tableLayoutPanel3.Controls.Add(buttonOkay, 1, 0);
|
||||
tableLayoutPanel3.Controls.Add(buttonCancel, 2, 0);
|
||||
tableLayoutPanel3.Controls.Add(labelCreatedUpdatedDT, 0, 0);
|
||||
tableLayoutPanel3.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel3.Location = new Point(3, 550);
|
||||
tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
tableLayoutPanel3.RowCount = 1;
|
||||
tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Absolute, 75F));
|
||||
tableLayoutPanel3.Size = new Size(1132, 69);
|
||||
tableLayoutPanel3.TabIndex = 2;
|
||||
//
|
||||
// buttonOkay
|
||||
//
|
||||
buttonOkay.Dock = DockStyle.Fill;
|
||||
buttonOkay.Location = new Point(735, 3);
|
||||
buttonOkay.Margin = new Padding(3, 3, 3, 15);
|
||||
buttonOkay.Name = "buttonOkay";
|
||||
buttonOkay.Size = new Size(194, 57);
|
||||
buttonOkay.TabIndex = 8;
|
||||
buttonOkay.Text = "Okay";
|
||||
buttonOkay.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
buttonCancel.Dock = DockStyle.Fill;
|
||||
buttonCancel.Location = new Point(935, 3);
|
||||
buttonCancel.Margin = new Padding(3, 3, 3, 15);
|
||||
buttonCancel.Name = "buttonCancel";
|
||||
buttonCancel.Size = new Size(194, 57);
|
||||
buttonCancel.TabIndex = 99;
|
||||
buttonCancel.TabStop = false;
|
||||
buttonCancel.Text = "Cancel";
|
||||
buttonCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// labelCreatedUpdatedDT
|
||||
//
|
||||
labelCreatedUpdatedDT.AutoSize = true;
|
||||
labelCreatedUpdatedDT.Dock = DockStyle.Fill;
|
||||
labelCreatedUpdatedDT.Location = new Point(3, 0);
|
||||
labelCreatedUpdatedDT.Name = "labelCreatedUpdatedDT";
|
||||
labelCreatedUpdatedDT.Size = new Size(726, 75);
|
||||
labelCreatedUpdatedDT.TabIndex = 2;
|
||||
labelCreatedUpdatedDT.Text = "Created: yyyy-mm-dd, Updated: yyyy-mm-dd";
|
||||
//
|
||||
// ProjectForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(13F, 32F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1144, 660);
|
||||
Controls.Add(groupBoxNewClient);
|
||||
Name = "ProjectForm";
|
||||
Text = "ProjectForm";
|
||||
groupBoxNewClient.ResumeLayout(false);
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel2.ResumeLayout(false);
|
||||
tableLayoutPanel2.PerformLayout();
|
||||
tableLayoutPanel6.ResumeLayout(false);
|
||||
tableLayoutPanel6.PerformLayout();
|
||||
tableLayoutPanel4.ResumeLayout(false);
|
||||
tableLayoutPanel4.PerformLayout();
|
||||
groupBoxNotes.ResumeLayout(false);
|
||||
tableLayoutPanel3.ResumeLayout(false);
|
||||
tableLayoutPanel3.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private GroupBox groupBoxNewClient;
|
||||
private TableLayoutPanel tableLayoutPanel1;
|
||||
private TableLayoutPanel tableLayoutPanel2;
|
||||
private Label labelClient;
|
||||
private Label labelName;
|
||||
private Label labelDescription;
|
||||
private Label labelStartDate;
|
||||
private Label labelHourlyRate;
|
||||
private TextBox textBoxName;
|
||||
private GroupBox groupBoxNotes;
|
||||
private RichTextBox richTextBoxNotes;
|
||||
private TableLayoutPanel tableLayoutPanel3;
|
||||
private Button buttonOkay;
|
||||
private Button buttonCancel;
|
||||
private Label labelCreatedUpdatedDT;
|
||||
private ComboBox comboBoxClient;
|
||||
private TableLayoutPanel tableLayoutPanel6;
|
||||
private DateTimePicker dateTimePickerStartDate;
|
||||
private DateTimePicker dateTimePickerEndDate;
|
||||
private Label labelEndDate;
|
||||
private RichTextBox richTextBoxDescription;
|
||||
private TableLayoutPanel tableLayoutPanel4;
|
||||
private Label labelBudget;
|
||||
private Label labelStatus;
|
||||
private ComboBox comboBoxStatus;
|
||||
private TextBox textBoxHourlyRate;
|
||||
private TextBox textBoxBudget;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
using System.ComponentModel;
|
||||
using trakker.Models;
|
||||
|
||||
namespace trakker.Forms
|
||||
{
|
||||
/// <summary>
|
||||
/// Form used to view and edit a <see cref="Project"/> model. Fields on the form
|
||||
/// are data-bound to the provided project instance and basic validation is
|
||||
/// performed on required fields.
|
||||
/// </summary>
|
||||
public partial class ProjectForm : Form
|
||||
{
|
||||
/// <summary>
|
||||
/// The project instance being edited by this form.
|
||||
/// </summary>
|
||||
private readonly Project _project;
|
||||
|
||||
private BindingList<Client>? _clients;
|
||||
|
||||
/// <summary>
|
||||
/// Binding source that connects the project model to the form controls.
|
||||
/// </summary>
|
||||
private BindingSource bindingSource = new BindingSource();
|
||||
|
||||
/// <summary>
|
||||
/// Error provider used to display validation errors next to input controls.
|
||||
/// </summary>
|
||||
private ErrorProvider errorProvider = new ErrorProvider();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProjectForm"/> class bound to
|
||||
/// the provided <paramref name="project"/>. Sets up data bindings for all
|
||||
/// visible input controls and configures dialog button behavior.
|
||||
/// </summary>
|
||||
/// <param name="project">The <see cref="Project"/> instance to edit. Must not be null.</param>
|
||||
/// <param name="clients">The list of <see cref="Client"/> instances to select from. Must not be null.</param>
|
||||
public ProjectForm(Project project, BindingList<Client> clients)
|
||||
{
|
||||
_project = project;
|
||||
_clients = clients;
|
||||
InitializeComponent();
|
||||
|
||||
comboBoxClient.DataSource = _clients;
|
||||
comboBoxClient.DisplayMember = "Name";
|
||||
comboBoxClient.ValueMember = "ClientId";
|
||||
|
||||
dateTimePickerStartDate.Format = DateTimePickerFormat.Custom;
|
||||
dateTimePickerStartDate.CustomFormat = "yyyy-MM-dd";
|
||||
dateTimePickerEndDate.Format = DateTimePickerFormat.Custom;
|
||||
dateTimePickerEndDate.CustomFormat = "yyyy-MM-dd";
|
||||
|
||||
// Bind model properties to controls so the UI reflects and updates the model.
|
||||
bindingSource.DataSource = _project;
|
||||
comboBoxClient.DataBindings.Add("SelectedValue", bindingSource, "ClientId", true);
|
||||
textBoxName.DataBindings.Add("Text", bindingSource, "ProjectName", true);
|
||||
richTextBoxDescription.DataBindings.Add("Text", bindingSource, "Description", true);
|
||||
dateTimePickerStartDate.DataBindings.Add("Value", bindingSource, "StartDate", true);
|
||||
dateTimePickerEndDate.DataBindings.Add("Value", bindingSource, "EndDate", true);
|
||||
textBoxHourlyRate.DataBindings.Add("Text", bindingSource, "HourlyRate", true);
|
||||
textBoxBudget.DataBindings.Add("Text", bindingSource, "Budget", true);
|
||||
comboBoxStatus.DataBindings.Add("ValueMember", bindingSource, "Status", true);
|
||||
richTextBoxNotes.DataBindings.Add("Text", bindingSource, "Notes", true);
|
||||
|
||||
// Configure dialog buttons and window behavior.
|
||||
buttonOkay.DialogResult = DialogResult.OK;
|
||||
buttonCancel.DialogResult = DialogResult.Cancel;
|
||||
this.CancelButton = buttonCancel;
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Project"/> instance edited by the form.
|
||||
/// </summary>
|
||||
public Project Project { get => _project; private set { } }
|
||||
|
||||
public BindingList<Client>? Clients { get => _clients; set { _clients = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Validates the Name field. If the name is empty or whitespace, an error is set
|
||||
/// on the <see cref="errorProvider"/> and the event is canceled to prevent the
|
||||
/// form from closing.
|
||||
/// </summary>
|
||||
private void textBoxName_Validating(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(textBoxName.Text))
|
||||
{
|
||||
errorProvider.SetError(textBoxName, "Name is required.");
|
||||
errorProvider.SetIconAlignment(textBoxName, ErrorIconAlignment.MiddleRight);
|
||||
errorProvider.SetIconPadding(textBoxName, 2);
|
||||
e.Cancel = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorProvider.SetError(textBoxName, "");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the Email field. If the email is empty or whitespace, an error is set
|
||||
/// on the <see cref="errorProvider"/> and the event is canceled to prevent the
|
||||
/// form from closing. Note: this validation only checks presence, not format.
|
||||
/// </summary>
|
||||
private void textBoxEmail_Validating(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
//if (string.IsNullOrWhiteSpace(textBoxEmail.Text))
|
||||
//{
|
||||
// errorProvider.SetError(textBoxEmail, "Email is required.");
|
||||
// errorProvider.SetIconAlignment(textBoxEmail, ErrorIconAlignment.MiddleRight);
|
||||
// errorProvider.SetIconPadding(textBoxEmail, 2);
|
||||
// e.Cancel = true;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// errorProvider.SetError(textBoxEmail, "");
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
|
@ -11,5 +11,7 @@ namespace trakker.Interfaces
|
|||
internal interface IMainForm
|
||||
{
|
||||
void InitDataGridViewClients(BindingList<Client> clients);
|
||||
void InitDataGridViewProjects();
|
||||
void FillDataGridViewProjects(BindingSource projects);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,31 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
||||
namespace trakker.Models
|
||||
{
|
||||
public class Project
|
||||
{
|
||||
[Key]
|
||||
public string ProjectId { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public string ClientId { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[MaxLength(200)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string ProjectCode { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(1000)]
|
||||
public string? Description { get; set; }
|
||||
public string ClientName { get; set; } = string.Empty;
|
||||
|
||||
public DateOnly? StartDate { get; set; }
|
||||
public string ProjectName { get; set; } = string.Empty;
|
||||
|
||||
public DateOnly? EndDate { get; set; }
|
||||
public string? Description { get; set; } = string.Empty;
|
||||
|
||||
public DateTime? StartDate { get; set; }
|
||||
|
||||
public DateTime? EndDate { get; set; }
|
||||
|
||||
[Range(0, double.MaxValue)]
|
||||
public decimal Budget { get; set; } = 0;
|
||||
|
||||
public ProjectStatus Status { get; set; } = ProjectStatus.Active;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
[Range(0, double.MaxValue)]
|
||||
public decimal? HourlyRate { get; set; }
|
||||
|
||||
[MaxLength(2000)]
|
||||
public string? Notes { get; set; }
|
||||
public string? Notes { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,36 @@ namespace trakker.Services
|
|||
_connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
|
||||
|
||||
LoadClients();
|
||||
|
||||
_view.InitDataGridViewProjects();
|
||||
LoadProjects();
|
||||
}
|
||||
|
||||
public BindingList<Client> GetClients()
|
||||
{
|
||||
var dbo = new Data.ClientData(_connectionString);
|
||||
return dbo.Get();
|
||||
}
|
||||
internal void LoadClients()
|
||||
{
|
||||
// Implement logic to load clients from the database using _connectionString
|
||||
var dbo = new Data.ClientData(_connectionString);
|
||||
var clients = dbo.Get();
|
||||
var clients = GetClients();
|
||||
_view.InitDataGridViewClients(clients);
|
||||
}
|
||||
|
||||
public BindingList<Project> GetProjects()
|
||||
{
|
||||
var dbo = new Data.ProjectData(_connectionString);
|
||||
return dbo.Get();
|
||||
}
|
||||
|
||||
internal void LoadProjects()
|
||||
{
|
||||
var projects = GetProjects();
|
||||
foreach (var project in projects)
|
||||
{
|
||||
var x = project.Status;
|
||||
}
|
||||
_view.FillDataGridViewProjects(new BindingSource { DataSource = projects });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,285 @@
|
|||
using Microsoft.Data.Sqlite;
|
||||
using System.ComponentModel;
|
||||
using trakker.Data;
|
||||
using trakker.Forms;
|
||||
using trakker.Interfaces;
|
||||
using trakker.Models;
|
||||
using trakker.Services;
|
||||
|
||||
namespace trakker
|
||||
{
|
||||
public partial class MainForm : Form, IMainForm
|
||||
{
|
||||
//private readonly string _dbversion = "[N.N.N]";
|
||||
private string connectionString = string.Empty;
|
||||
readonly MainCtrl _ctrl;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MainForm"/> class.
|
||||
/// Sets up the form's controls and event handlers by calling
|
||||
/// <see cref="InitializeComponent"/> which is generated by the designer.
|
||||
/// </summary>
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// build connection string that will be used for database connections
|
||||
// ------------------------------------------------------------------------
|
||||
var dbPath = Path.Combine(AppContext.BaseDirectory, "trakker.db");
|
||||
connectionString = new SqliteConnectionStringBuilder
|
||||
{
|
||||
DataSource = dbPath,
|
||||
Mode = SqliteOpenMode.ReadWriteCreate,
|
||||
Cache = SqliteCacheMode.Shared
|
||||
}.ToString();
|
||||
|
||||
tabControlMainForm.TabPages[0].Text = " Home ";
|
||||
tabControlMainForm.TabPages[1].Text = " Clients ";
|
||||
tabControlMainForm.TabPages[2].Text = " Projects ";
|
||||
|
||||
_ctrl = new Services.MainCtrl(this, connectionString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the Click event of the Exit menu item. When invoked, this
|
||||
/// method terminates the application.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">Event data associated with the click event.</param>
|
||||
private void MainForm_Exit_MenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
public void InitDataGridViewClients(BindingList<Client> clients)
|
||||
{
|
||||
dataGridViewClients.AllowUserToAddRows = true;
|
||||
dataGridViewClients.AllowUserToDeleteRows = true;
|
||||
dataGridViewClients.AutoGenerateColumns = false;
|
||||
dataGridViewClients.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||
dataGridViewClients.BackgroundColor = Color.White;
|
||||
dataGridViewClients.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dataGridViewClients.RowHeadersVisible = false;
|
||||
dataGridViewClients.ColumnHeadersVisible = true;
|
||||
dataGridViewClients.MultiSelect = false;
|
||||
dataGridViewClients.DataSource = clients;
|
||||
|
||||
dataGridViewClients.Columns.Clear();
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Name",
|
||||
Name = "Name",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewClients.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Company",
|
||||
Name = "Company",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewClients.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Email",
|
||||
Name = "Email",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewClients.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Phone",
|
||||
Name = "Phone",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewClients.Columns.Add(textColumn);
|
||||
}
|
||||
|
||||
dataGridViewClients.DoubleClick += (s, e) =>
|
||||
{
|
||||
if (dataGridViewClients.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedClient = dataGridViewClients.SelectedRows[0].DataBoundItem as Client;
|
||||
if (selectedClient != null)
|
||||
{
|
||||
var dialog = new ClientForm(selectedClient);
|
||||
if (dialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
Client client = dialog.Client;
|
||||
ClientData clientData = new ClientData(connectionString);
|
||||
try
|
||||
{
|
||||
clientData.Upsert(client);
|
||||
dataGridViewClients.Refresh(); // Refresh the DataGridView to reflect changes
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error saving client: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dataGridViewClients.SelectionChanged += (s, e) =>
|
||||
{
|
||||
if (dataGridViewClients.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedClient = dataGridViewClients.SelectedRows[0].DataBoundItem as Client;
|
||||
if (selectedClient != null)
|
||||
{
|
||||
// Handle the selected client as needed
|
||||
// MessageBox.Show($"Selected Client: {selectedClient.AddressStreet}", "Client Selected", MessageBoxButtons.OK, MessageBoxIcon.Information );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
public void InitDataGridViewProjects(BindingList<Project> projects)
|
||||
{
|
||||
dataGridViewProjects.AllowUserToAddRows = true;
|
||||
dataGridViewProjects.AllowUserToDeleteRows = true;
|
||||
dataGridViewProjects.AutoGenerateColumns = false;
|
||||
dataGridViewProjects.BackgroundColor = Color.White;
|
||||
dataGridViewProjects.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dataGridViewProjects.RowHeadersVisible = false;
|
||||
dataGridViewProjects.ColumnHeadersVisible = true;
|
||||
dataGridViewProjects.MultiSelect = false;
|
||||
dataGridViewProjects.DataSource = projects;
|
||||
dataGridViewProjects.Columns.Clear();
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "ProjectName",
|
||||
Name = "Project Name",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "ClientName",
|
||||
Name = "Client Name",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "StartDate",
|
||||
Name = "Start Date",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "EndDate",
|
||||
Name = "End Date",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Status",
|
||||
Name = "Status",
|
||||
Visible = true,
|
||||
};
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
{
|
||||
var textColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||||
DataPropertyName = "Budget",
|
||||
Name = "Budget",
|
||||
Visible = true,
|
||||
};
|
||||
textColumn.DefaultCellStyle.Format = "$#,##0.00";
|
||||
textColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
|
||||
textColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight;
|
||||
dataGridViewProjects.Columns.Add(textColumn);
|
||||
}
|
||||
|
||||
dataGridViewProjects.DoubleClick += (s, e) =>
|
||||
{
|
||||
if (dataGridViewProjects.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedProject = dataGridViewProjects.SelectedRows[0].DataBoundItem as Project;
|
||||
if (selectedProject != null)
|
||||
{
|
||||
var dialog = new ProjectForm(selectedProject);
|
||||
if (dialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
// Project project = dialog.Project;
|
||||
// ProjectData projectData = new ProjectData(connectionString);
|
||||
// try
|
||||
// {
|
||||
// projectData.Upsert(project);
|
||||
// dataGridViewProjects.Refresh(); // Refresh the DataGridView to reflect changes
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// MessageBox.Show($"Error saving project: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dataGridViewClients.SelectionChanged += (s, e) =>
|
||||
{
|
||||
if (dataGridViewClients.SelectedRows.Count > 0)
|
||||
{
|
||||
var selectedClient = dataGridViewClients.SelectedRows[0].DataBoundItem as Client;
|
||||
if (selectedClient != null)
|
||||
{
|
||||
// Handle the selected client as needed
|
||||
// MessageBox.Show($"Selected Client: {selectedClient.AddressStreet}", "Client Selected", MessageBoxButtons.OK, MessageBoxIcon.Information );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//private void button1_Click(object sender, EventArgs e)
|
||||
//{
|
||||
// var dialog = new ClientForm(new Client());
|
||||
// if (dialog.ShowDialog(this) == DialogResult.OK)
|
||||
// {
|
||||
// Client client = dialog.Client;
|
||||
// ClientData clientData = new ClientData(connectionString);
|
||||
// try
|
||||
// {
|
||||
// clientData.Upsert(client);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// MessageBox.Show($"Error saving client: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue