This question provides the code behind the dialogs in the C# refactoring question. I'd like a review of this code as well. I'm not currently using databinding anywhere, and there is really only one place that it might help which is in the add or edit tenant form. This question is separate from the other question because there is too much code to present in one question.
Visual Studio generated code is not included in this question.
Features
- Generate MS Word documents from the data in the Excel spreadsheet for use as directories by mailboxes.
- Add or Edit a tenant to the complex.
- Delete a tenant from the complex.
- Set preferences for when to save or print a file. Where to store saved Word documents. Where to find the Excel spreadsheet file.
- Save any current changes.
- The data is saved automatically when the program exits.
- If the Excel file is open in another application it warns the user and will not start. If the user open it in Excel after the program starts it warns them that the changes can't be saved until the Excel file is closed.
RentRosterApp.cs
This is the main form started by the Program.cs module, consider it a control panel, it only contains buttons that open other dialogs. It does however contain some program logic for global initialization.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TenantRosterAutomation
{
public partial class RentRosterApp : Form
{
private bool globalsInitialized;
public RentRosterApp()
{
globalsInitialized = Globals.InitializeAllModels();
InitializeComponent();
}
private void RentRosterApp_Load(object sender, EventArgs e)
{
RR_Quit_BTN.BackColor = Color.Red;
if (!globalsInitialized)
{
PrintMailboxLists_Button.Enabled = false;
AddNewResident_Button.Enabled = false;
DeleteRenter_Button.Enabled = false;
using (EditPreferencesDlg preferences_dlg = new EditPreferencesDlg())
{
if (preferences_dlg.ShowDialog() == DialogResult.OK)
{
PrintMailboxLists_Button.Enabled = true;
AddNewResident_Button.Enabled = true;
DeleteRenter_Button.Enabled = true;
}
}
}
}
private void PrintMailboxLists_Button_Click(object sender, EventArgs e)
{
PrintMailboxListsDlg printMailboxLists_dialog = new PrintMailboxListsDlg();
printMailboxLists_dialog.Show();
}
private void AddNewResident_Button_Click(object sender, EventArgs e)
{
ApartmentNumberVerifier verifier_Form = new ApartmentNumberVerifier();
verifier_Form.NextAction = ApartmentNumberVerifier.NextActionEnum.ADD;
verifier_Form.Show();
}
private void DeleteRenter_Button_Click(object sender, EventArgs e)
{
ApartmentNumberVerifier verifier_Form = new ApartmentNumberVerifier();
verifier_Form.NextAction = ApartmentNumberVerifier.NextActionEnum.DELETE;
verifier_Form.Show();
}
private void EditPreferences_BTN_Click(object sender, EventArgs e)
{
EditPreferencesDlg preferences_dlg = new EditPreferencesDlg();
preferences_dlg.Show();
}
private void RR_Quit_BTN_Click(object sender, EventArgs e)
{
try
{
Globals.Save();
Globals.ReleaseAllModels();
Close();
}
catch (AlreadyOpenInExcelException ao)
{
MessageBox.Show(ao.Message);
}
}
private void RR_SAVEEDITS_BTN_Click(object sender, EventArgs e)
{
try
{
Globals.SaveTenantData();
}
catch (AlreadyOpenInExcelException ao)
{
MessageBox.Show(ao.Message);
}
}
private void RentRosterApp_FormClosing(object sender, FormClosingEventArgs e)
{
// Save all changes before quiting.
Globals.Save();
Globals.ReleaseAllModels();
}
}
}
EditPreferencesDlg.cs
This form allows the users to edit their preferences, it is called with a button on the main control panel, but if the preferences have never been created before then the control panel opens it automatically. There might be a fairly strong coupling between this class and the UserPreferences
class.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace TenantRosterAutomation
{
public partial class EditPreferencesDlg : Form
{
private UserPreferences localPreferences;
public EditPreferencesDlg()
{
localPreferences = new UserPreferences();
localPreferences.CopyValues(Globals.Preferences, true);
InitializeComponent();
}
private void EditPreferencesDlg_Load(object sender, EventArgs e)
{
EP_Cancel_BTN.BackColor = Color.Red;
EP_SavePreferences_BTN.BackColor = Color.Green;
EP_DefaultFileFolder_TB.Text = localPreferences.DefaultSaveDirectory;
EP_RentRosterLocation_TB.Text = localPreferences.ExcelWorkBookFullFileSpec;
EP_SheetName_TB.Text = localPreferences.ExcelWorkSheetName;
switch (localPreferences.PrintSaveOptions)
{
case PrintSavePreference.PrintSave.PrintAndSave:
EP_PrintAndSave_RB.Checked = true;
break;
case PrintSavePreference.PrintSave.SaveOnly:
EP_SavelOnly_RB.Checked = true;
break;
default:
EP_PrintOnly_RB.Checked = true;
break;
}
EP_SheetName_TB.Enabled = false;
EP_RentRosterSheetName_LISTBOX.Visible = false;
}
private void EP_PrintAndSave_RB_CheckedChanged(object sender, EventArgs e)
{
localPreferences.PrintSaveOptions = PrintSavePreference.PrintSave.PrintAndSave;
}
private void EP_SavelOnly_RB_CheckedChanged(object sender, EventArgs e)
{
localPreferences.PrintSaveOptions = PrintSavePreference.PrintSave.SaveOnly;
}
private void EP_PrintOnly_RB_CheckedChanged(object sender, EventArgs e)
{
localPreferences.PrintSaveOptions = PrintSavePreference.PrintSave.PrintOnly;
}
private void EP_DefaultFileFolder_TB_TextChanged(object sender, EventArgs e)
{
localPreferences.DefaultSaveDirectory = EP_DefaultFileFolder_TB.Text;
}
private void findDefaultFolderLocationExecute(object sender, EventArgs e)
{
using (var fbd = new FolderBrowserDialog())
{
DialogResult result = fbd.ShowDialog();
if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
{
EP_DefaultFileFolder_TB.Text = fbd.SelectedPath;
localPreferences.DefaultSaveDirectory = fbd.SelectedPath;
}
}
}
private void EP_DefaultFileFolder_TB_Click(object sender, EventArgs e)
{
findDefaultFolderLocationExecute(sender, e);
}
private void EP_BrowseFolderLocation_BTN_Click(object sender, EventArgs e)
{
findDefaultFolderLocationExecute(sender, e);
}
private void EP_RentRosterLocation_TB_TextChanged(object sender, EventArgs e)
{
localPreferences.ExcelWorkBookFullFileSpec = EP_RentRosterLocation_TB.Text;
}
private void findTenantRosterExcelFile(object sender, EventArgs e)
{
string tenantRosterFile = "";
OpenFileDialog FindTenantRoster = new OpenFileDialog();
FindTenantRoster.InitialDirectory = "c:\\";
FindTenantRoster.Filter = "Excel Files| *.xls; *.xlsx; *.xlsm";
if (FindTenantRoster.ShowDialog() == DialogResult.OK)
{
tenantRosterFile = FindTenantRoster.FileName;
EP_RentRosterLocation_TB.Text = tenantRosterFile;
localPreferences.ExcelWorkBookFullFileSpec = tenantRosterFile;
}
}
private void fillSheetSelectorListBox()
{
List<string> sheetNames = null;
if (!string.IsNullOrEmpty(localPreferences.ExcelWorkBookFullFileSpec))
{
ExcelFileData ExcelFile = new ExcelFileData(localPreferences.ExcelWorkBookFullFileSpec,
localPreferences.ExcelWorkSheetName);
sheetNames = ExcelFile.GetWorkSheetCollection();
}
if (sheetNames == null)
{
return;
}
EP_RentRosterSheetName_LISTBOX.DataSource = sheetNames;
EP_RentRosterSheetName_LISTBOX.Visible = true;
EP_SheetName_TB.Enabled = true;
}
private void EP_FindRenterRoster_BTN_Click(object sender, EventArgs e)
{
findTenantRosterExcelFile(sender, e);
fillSheetSelectorListBox();
}
private void EP_RentRosterLocation_TB_Click(object sender, EventArgs e)
{
findTenantRosterExcelFile(sender, e);
fillSheetSelectorListBox();
}
private void EP_RentRosterSheetName_LISTBOX_SelectedIndexChanged(object sender, EventArgs e)
{
localPreferences.ExcelWorkSheetName = EP_RentRosterSheetName_LISTBOX.SelectedItem.ToString();
EP_SheetName_TB.Text = localPreferences.ExcelWorkSheetName;
}
private void EP_SheetName_TB_Click(object sender, EventArgs e)
{
fillSheetSelectorListBox();
}
private void EP_SavePreferences_BTN_Click(object sender, EventArgs e)
{
// Make sure any previous edits to the tenant are saved
// then reset all the models.
Globals.Save();
Globals.ReInitizeAllModels(localPreferences);
Globals.SavePreferences();
DialogResult = DialogResult.OK;
Close();
}
private void EP_Cancel_Button_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
}
}
PrintMailboxListsDlg.cs
This form allows the user to print and or save word documents created from the excel data. It also allows the user to override some of their preferences on a case by case basis.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace TenantRosterAutomation
{
public partial class PrintMailboxListsDlg : Form
{
private PrintSavePreference.PrintSave printSave;
private bool addDateToFileName = false;
private bool addDateToTitle = false;
private string selectedBuildings;
private MSWordInterface wordInteropMethods;
public PrintMailboxListsDlg()
{
InitializeComponent();
wordInteropMethods = new MSWordInterface(Globals.Preferences);
}
private void PrintMailboxLists_Form_Load(object sender, EventArgs e)
{
List<string> buildings = Globals.Complex.BuildingAddressList;
foreach (string building in buildings)
{
SelectBuilding2Print_listBox.Items.Add(building);
}
SelectBuilding2Print_listBox.Items.Add("All Buildings");
if (Globals.Preferences.HavePreferenceData)
{
printSave = Globals.Preferences.PrintSaveOptions;
PrintSaveChange();
}
AddDateToFileName_CB.Checked = addDateToFileName;
AddDateUnderAddress_CB.Checked = addDateToTitle;
PML_SaveAndPrint_Button.Enabled = false;
}
private void AddDateToFileName_CB_CheckedChanged(object sender, EventArgs e)
{
addDateToFileName = !addDateToFileName;
}
private void AddDateUnderAddress_CB_CheckedChanged(object sender, EventArgs e)
{
addDateToTitle = !addDateToTitle;
}
private void PML_SaveAndPrint_Button_Click(object sender, EventArgs e)
{
if (String.Compare(selectedBuildings, "All Buildings") == 0)
{
List<int> StreetNumbers = Globals.Complex.StreetNumbers;
foreach (int streetNumber in StreetNumbers)
{
printAndOrSaveMailList(streetNumber);
}
}
else
{
string streetAddress = selectedBuildings.Substring(0, 5);
printAndOrSaveMailList(streetAddress);
}
Close();
}
private void printAndOrSaveMailList(string streetAddress)
{
int iStreetNumber = 0;
if (Int32.TryParse(streetAddress, out iStreetNumber))
{
printAndOrSaveMailList(iStreetNumber);
}
else
{
MessageBox.Show("Non Numeric string passed into PrintMailboxLists_Form::printAndOrSaveMailList().");
}
}
private void PML_PrintOnly_RB_CheckedChanged(object sender, EventArgs e)
{
printSave = PrintSavePreference.PrintSave.PrintOnly;
}
private void PML_SavelOnly_RB_CheckedChanged(object sender, EventArgs e)
{
printSave = PrintSavePreference.PrintSave.SaveOnly;
}
private void PML_PrintAndSave_RB_CheckedChanged(object sender, EventArgs e)
{
printSave = PrintSavePreference.PrintSave.PrintAndSave;
}
private void PrintSaveChange()
{
switch (printSave)
{
case PrintSavePreference.PrintSave.PrintAndSave:
PML_PrintAndSave_RB.Checked = true;
break;
case PrintSavePreference.PrintSave.SaveOnly:
PML_SavelOnly_RB.Checked = true;
break;
default:
PML_PrintOnly_RB.Checked = true;
break;
}
}
private void SelectBuilding2Print_listBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (SelectBuilding2Print_listBox.SelectedItem != null)
{
selectedBuildings = SelectBuilding2Print_listBox.SelectedItem.ToString();
PML_SaveAndPrint_Button.Enabled = true;
}
}
private void printAndOrSaveMailList(int streetAddress)
{
bool save = ((printSave == PrintSavePreference.PrintSave.PrintAndSave) ? true :
(printSave == PrintSavePreference.PrintSave.SaveOnly) ? true : false);
bool print = ((printSave == PrintSavePreference.PrintSave.PrintAndSave) ? true :
(printSave == PrintSavePreference.PrintSave.PrintOnly) ? true : false);
string documentName = "MailboxList_" + streetAddress;
string statusMessage = (print && save) ? "Printing and Saving " :
(print) ? "Printing " : "Saving ";
statusMessage += "the mailbox list for " + streetAddress;
ReportCurrentStatusWindow psStatus = new ReportCurrentStatusWindow();
psStatus.MessageText = statusMessage;
psStatus.Show();
Building building = Globals.Complex.GetBuilding(streetAddress);
if (building != null)
{
MailboxData mailboxList = Globals.Complex.GetMailBoxList(building);
if (mailboxList != null)
{
wordInteropMethods.CreateMailistPrintAndOrSave(documentName,
mailboxList, addDateToFileName, addDateToTitle, save, print);
}
}
psStatus.Close();
}
}
}
ApartmentNumberVerifier.cs
This form presents only a textbox and a button. It is called prior to calling either the Add or Edit Tenant Dialog or the Delete Tenant Dialog. The purpose of the dialog is to find the correct tenant by apartment number.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TenantRosterAutomation
{
public partial class ApartmentNumberVerifier : Form
{
public enum NextActionEnum
{
ADD,
DELETE,
EDIT
}
public int ApartmentNumber;
public Tenant TenantData { get; private set; }
public NextActionEnum NextAction { get; set; }
public ApartmentNumberVerifier()
{
TenantData = null;
InitializeComponent();
}
private void APV_FindApartment_BTN_Click(object sender, EventArgs e)
{
VerifyApartmentNumber();
}
private void ANV_ApartmentNumber_TB_TextChanged(object sender, EventArgs e)
{
ANV_FindApartment_BTN.Enabled = true;
}
private void ApartmentNumberVerifier_Form_Load(object sender, EventArgs e)
{
ANV_FindApartment_BTN.Enabled = false;
ANV_ApartmentNumber_TB.KeyDown += new KeyEventHandler(ANV_ApartmentNumber_TB_KeyDown);
}
private void ANV_ApartmentNumber_TB_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
VerifyApartmentNumber();
}
}
private void ErrorActions(string errorMessage)
{
ANV_ApartmentNumber_TB.BackColor = Color.Yellow;
ANV_ApartmentNumber_TB.Text = "";
MessageBox.Show(errorMessage);
ActiveControl = ANV_ApartmentNumber_TB;
}
private bool ReportErrors(int aptNumber, PropertyComplex.ApartmentNumberValid validApartmentId)
{
bool hasErrors = false;
string errorMessage = null;
switch (validApartmentId)
{
case PropertyComplex.ApartmentNumberValid.APARTMENT_NUMBER_NONNUMERIC:
errorMessage = "Please enter a number in the box.";
break;
case PropertyComplex.ApartmentNumberValid.APARTMENT_NUMBER_OUT_OF_RANGE:
int minAptNo = Globals.Complex.MinApartmentNumber;
int maxAptNo = Globals.Complex.MaxApartmentNumber;
errorMessage = "The apartment number: " + aptNumber.ToString() +
" is out of range[" + minAptNo.ToString() +
", " + maxAptNo.ToString() + "] please enter a valid apartment number.";
break;
case PropertyComplex.ApartmentNumberValid.APARTMENT_NUMBER_NOT_FOUND:
errorMessage = "The number entered: " + aptNumber +
" was not found in the list of apartments.";
break;
default:
break;
}
if (!string.IsNullOrEmpty(errorMessage))
{
ErrorActions(errorMessage);
hasErrors = true;
}
return hasErrors;
}
private void VerifyApartmentNumber()
{
int aptNumber = 0;
PropertyComplex.ApartmentNumberValid validApartmentId =
Globals.Complex.VerifyApartmentNumber(ANV_ApartmentNumber_TB.Text, out aptNumber);
if (ReportErrors(aptNumber, validApartmentId))
{
return;
}
ExecuteNextgAction(aptNumber);
Close();
}
private void ExecuteNextgAction(int aptNumber)
{
TenantData = Globals.TenantRoster.GetTenant(aptNumber);
switch (NextAction)
{
case NextActionEnum.EDIT:
case NextActionEnum.ADD:
AddOrEditResidentDlg addNewResident = new AddOrEditResidentDlg();
addNewResident.CurrentTenant = TenantData;
addNewResident.ApartmentNumber = aptNumber;
addNewResident.Show();
break;
case NextActionEnum.DELETE:
DeleteRenterDlg deleteRenter_dlg = new DeleteRenterDlg();
deleteRenter_dlg.CurrentTenant = TenantData;
deleteRenter_dlg.ApartmentNumber = aptNumber;
deleteRenter_dlg.Show();
break;
default:
MessageBox.Show("Programmer error: NextAction = " +
NextAction.ToString() +
" this action is not implemented.");
break;
}
}
}
}
AddOrEditResidentDlg.cs
This form allows the data in the excel file to be changed by either adding or editing the tenant information. This changes are saved in the TenantDataTable until the user either clicks the Save button or the Quit button. Both actions will save the data to the Excel spreadsheet.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TenantRosterAutomation
{
public partial class AddOrEditResidentDlg : Form
{
public int ApartmentNumber { get; set; }
public Tenant CurrentTenant { get; set; }
public AddOrEditResidentDlg()
{
InitializeComponent();
}
private void ANR_SaveNewTenant_BTN_Click(object sender, EventArgs e)
{
CurrentTenant.LastName = ANR_TenantLastName_TB.Text;
CurrentTenant.FirstName = ANR_TenantFirstName_TB.Text;
CurrentTenant.LeaseStart = ANR_MoveInDate_TB.Text;
CurrentTenant.LeaseEnd = ANR_LeaseEnd_TB.Text;
CurrentTenant.HomePhone = ANR_HomePhone_TB.Text;
CurrentTenant.CoTenantLastName = ANR_CoTenantLastName_TB.Text;
CurrentTenant.CoTenantFirstName = ANR_AdditionalOccupantFirstName_TB.Text;
CurrentTenant.RentersInsurancePolicy = ANR_RenterInsurance_TB.Text;
CurrentTenant.Email = ANR_AlternateContact_TB.Text;
Globals.TenantRoster.AddEditTenant(ApartmentNumber, CurrentTenant);
Close();
}
private void AddNewResident_Form_Load(object sender, EventArgs e)
{
SetUpApartmentAddressLabel();
ANR_SaveNewTenant_BTN.BackColor = Color.Green;
ANR_Cancel_BTN.BackColor = Color.Red;
if (CurrentTenant != null)
{
ANR_TenantLastName_TB.Text = CurrentTenant.LastName;
ANR_TenantFirstName_TB.Text = CurrentTenant.FirstName;
ANR_HomePhone_TB.Text = CurrentTenant.HomePhone;
ANR_MoveInDate_TB.Text = CurrentTenant.LeaseStart;
ANR_LeaseEnd_TB.Text = CurrentTenant.LeaseEnd;
ANR_CoTenantLastName_TB.Text = CurrentTenant.CoTenantLastName;
ANR_AdditionalOccupantFirstName_TB.Text = CurrentTenant.CoTenantFirstName;
ANR_AlternateContact_TB.Text = CurrentTenant.Email;
ANR_RenterInsurance_TB.Text = CurrentTenant.RentersInsurancePolicy;
}
}
private void SetUpApartmentAddressLabel()
{
string apartmentFullAddress = ApartmentNumber.ToString();
string buildingAddress =
Globals.Complex.FindBuildingByApartment(ApartmentNumber);
if (!string.IsNullOrEmpty(buildingAddress))
{
apartmentFullAddress = buildingAddress + " Apartment " + ApartmentNumber.ToString();
ANR_ApartmentNumber_Label.Text = apartmentFullAddress;
}
else
{
ANR_ApartmentNumber_Label.Text = "Apartment Number: " + apartmentFullAddress;
}
ANR_ApartmentNumber_Label.Font = new Font("Arial", 12, FontStyle.Bold);
}
private void ANR_Cancel_BTN_Click(object sender, EventArgs e)
{
Close();
}
}
}
DeleteRenterDlg.cs
This form allow sht user to delete a tenant from the apartment complex. The changes are also stored in the TenantDataTable.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TenantRosterAutomation
{
public partial class DeleteRenterDlg : Form
{
public int ApartmentNumber { get; set; }
public Tenant CurrentTenant { get; set; }
public DeleteRenterDlg()
{
ApartmentNumber = 0;
CurrentTenant = null;
InitializeComponent();
}
private void DR_DeleteRenter_BTN_Click(object sender, EventArgs e)
{
Globals.TenantRoster.DeleteTenant(ApartmentNumber);
Close();
}
private void DeleteRenter_Load(object sender, EventArgs e)
{
if (ApartmentNumber != 0 && CurrentTenant != null)
{
SetUpApartmentAddressLabel();
DR_DeleteRenter_BTN.Enabled = false;
DR_DeleteRenter_BTN.BackColor = Color.Red;
DR_Cancel_BTN.BackColor = Color.Green;
DR_TenantName_TB.Enabled = false;
DR_TenantName_TB.Text = CurrentTenant.mergedName();
}
}
private void SetUpApartmentAddressLabel()
{
string apartmentFullAddress = ApartmentNumber.ToString();
string buildingAddress =
Globals.Complex.FindBuildingByApartment(ApartmentNumber);
if (!string.IsNullOrEmpty(buildingAddress))
{
apartmentFullAddress = buildingAddress + " Apartment " + ApartmentNumber.ToString();
DR_AptNumber_LAB.Text = apartmentFullAddress;
}
else
{
DR_AptNumber_LAB.Text = "Apartment Number: " + apartmentFullAddress;
}
DR_AptNumber_LAB.Font = new Font("Arial", 12, FontStyle.Bold);
}
private void DR_Renter2DeleteYes_RB_CheckedChanged(object sender, EventArgs e)
{
DR_DeleteRenter_BTN.Enabled = true;
DR_DeleteRenter_BTN.BackColor = Color.Green;
DR_Cancel_BTN.BackColor = Color.Red;
}
private void DR_Renter2DeleteNo_RB_CheckedChanged(object sender, EventArgs e)
{
DR_DeleteRenter_BTN.Enabled = false;
DR_DeleteRenter_BTN.BackColor = Color.Red;
DR_Cancel_BTN.BackColor = Color.Green;
}
private void DR_Cancel_BTN_Click(object sender, EventArgs e)
{
Close();
}
}
}
ReportCurrentStatusWindow.cs
This form is used to present information to the user about the current status of the program it is only used during operations that can take noticible time such as reading the excel data file or writing the updates to the excel data file.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TenantRosterAutomation
{
public partial class ReportCurrentStatusWindow : Form
{
public string MessageText { get; set; }
public ReportCurrentStatusWindow()
{
InitializeComponent();
}
private void Form_CurrentProgressStatus_Load(object sender, EventArgs e)
{
CPS_Message_TB.Text = MessageText;
CPS_Message_TB.Font = new Font("Arial", 12, FontStyle.Bold);
Size size = TextRenderer.MeasureText(CPS_Message_TB.Text, CPS_Message_TB.Font);
Height = (size.Height * 3) + 84;
Width = size.Width + 84;
CPS_Message_TB.Width = size.Width;
CPS_Message_TB.Height = size.Height * 3;
CPS_Message_TB.Left = 40;
CPS_Message_TB.Height = 40;
}
}
}
INotifyPropertyChanged
? Also take care about field/property names:Snake_Case
is not a thing to use in C#. Avoid absolute pixel-sizing or pixel-positioning, use panels like FlowLayoutPanel/TableLayoutPanel to arrange the UI components instead. \$\endgroup\$