Ok so I have a form I'm building that's going to change it's interface by using custom controls. What I'm trying to do is make several checks before a new control is created, like checking if one is already up. I have everything working just fine but I can't seem to create the new control dynamically, without creating it before running the checks which defeats the purpose.
The controls all implement an interface called ICustomControl and inherit from a MasterControl. Then I have a custom control called JobForm, and a button on the main form that calls the method like so: Check_Controls(newJobForm)
JobForm newJobForm;
private void Check_Controls(Control control) // Checks current controls to see if a new one can be opened
{
bool currentControl = false;
foreach (Control c in this.Controls)
{
if (c is ICustomControl && c != masterControl)
currentControl = true;
}
if (currentControl)
{
TimedMessageBox timedMessage = new TimedMessageBox("There is currently an open form. Please close the current control before opening another.");
timedMessage.ShowDialog();
}
else
{
Control c = (Control)Activator.CreateInstance(control.GetType());
this.Controls.Add(c);
Position_Control(c);
c.Show();
}
}
I dont't want to create a new instance of the custom control like: JobForm newJobForm = new JobForm(); before running the check method, I want to pass the reference to the check method and then have it create the new instance after it's checks are complete. In this way no matter how many new custom controls I wind up adding to the application, all I have to do to set one up is create the reference variable, then for the button call the check method and pass it the reference.
Anyone know how I can do this?
I think you are thinking about the problem backwards. Instead of saying "I have control X, is it valid?" think "would control X be valid, if so create". You are wanting to make checks to see if a control is valid, yet you want to send in a reference to that control.
Your code doesn't check for specific types of control, but rather just that at least one control belonging to the current form implements your interface. If this is the intended behavior, just have a function that does your initial check to see if any ICustomControl exist on your form. If that function return false, then go along with your creation.
You can accomplish this with a single function by using a constrained generic. This also gets you away from the less-than-ideal practice of using Activator and other reflection methods for dynamic type generation:
private void CheckAndAddControl<ControlType>()
where ControlType : MasterControl, new()
{
bool currentControl = false;
foreach (Control c in this.Controls)
{
if (c is ControlType)
{
currentControl = true;
break;
}
}
if (currentControl)
{
TimedMessageBox timedMessage = new TimedMessageBox("There is currently an open form. Please close the current control before opening another.");
timedMessage.ShowDialog();
}
else
{
var c = new ControlType();
this.Controls.Add(c);
Position_Control(c);
c.Show();
}
}
You would then use this function as follows:
CheckAndAddControl<JobForm>();
Related
I use a binding source so that all my controls are bound to datasource. Like this:
var category = categoryRequest.Get(id);
bindingSource.DataSource = category;
This works fine.
I've also implemented INotifyPropertyChanged on the DTO classes (even though this should not be done), so that a change in the object's properties is reflected immediately in the corresponding controls. This also works.
However, if the user loads an object, changes some text in some controls and decides to close the form, I would like to determine if data has been changed and prompt a "Are you sure?" message.
Currently, the way I'm doing it is like this:
public static bool DataChanged(this Form form)
{
bool changed = false;
if (form == null)
return changed;
foreach (Control c in form.Controls)
{
switch (c.GetType().ToString())
{
case "TextBox":
changed = ((TextBox)c).Modified;
break;
//Other control types here...
}
if (changed)
break;
}
return changed;
}
But I don't think this is the best way to do it because:
Each control type needs to the added manually
Checking if lists have changed won't work
Is there a better way to achieve what I need?
Do you want to check it only once? Like before closing the window.. If you do you can
declare public static bool changed=false; in the form class and change its value to true from where you have implimented the INotifyPropertychanged.
you can display a messagebox anywhere in the form as follows.
if(changed)
{
if (MessageBox.Show("Are you sure?","some caption",MessageBoxButtons.YesNo)==DialogResult.Yes)
{
//Do this if user presses YES
}
}
I realize this is an older thread, but I would suggest a simple solution:
if (YourTextBox.Modified)
{
// Your code goes here.
}
I think it has been around since version 1.0. You will find further information here.
Just subscribe to the BindingSource's ListChanged event and set an IsDirty flag based on the event.
categoryBindingSource.ListChanged += new System.ComponentModel.ListChangedEventHandler(categoryBindingSource_ListChanged);
and set IsDirty = true in the event method...
void customerAccountBindingSource_ListChanged(object sender, system.ComponentModel.ListChangedEventArgs e)
{
if (e.ListChangedType == System.ComponentModel.ListChangedType.ItemChanged)
_isDirty = true;
}
I'm developing a WinForm application and I've done a pretty bad job thus far of managing the size and contents. I was hoping someone could give me an example of how to break out some of the logic that I have within the main form cs file.
Here is an example of an EventHandler function that I have within my MainWindow.cs:
private void GroupBoxRequestTypeCheckedChanged(object pSender, EventArgs pEventArgs)
{
RadioButton vRadioButton = pSender as RadioButton;
if (vRadioButton != null)
{
this.fSelectedButton = vRadioButton.Checked ? vRadioButton : null;
if (vRadioButton.Equals(this.RadioButton_Copy) || vRadioButton.Equals(this.RadioButton_Delete) || vRadioButton.Equals(this.RadioButton_Download)
|| vRadioButton.Equals(this.RadioButton_Move) || vRadioButton.Equals(this.RadioButton_Upload))
{
this.GroupBox_Files.Enabled = true;
this.GroupBox_Variables.Enabled = false;
}
else
{
this.GroupBox_Files.Enabled = false;
this.GroupBox_Variables.Enabled = true;
}
if (this.fSelectedButton != null)
{
if (this.fSelectedButton.Equals(this.RadioButton_Delete))
{
this.TextBox_DestinationFile.Enabled = false;
this.Button_DestinationBrowse.Enabled = false;
}
else
{
this.TextBox_DestinationFile.Enabled = true;
this.Button_DestinationBrowse.Enabled = true;
}
}
}
}
So this is simply one of many EventHandler's that I have within a Form. I created a MainForm which has a Tabbed Pane and has a collection of Tabs which have buttons, textboxes, checkboxes etc in each tab. All of the events that I handle go into the MainForm.cs file and now I've got close to 1,000 lines in this one file.
Can someone give me a simple example (or a article/document) detailing good structure? Can I define my EventHandler functions in a separate class (if so, how would this work...) Do I create some sort of static Helper class where I simply pass the instance of the objects i need to manipulate? I.E.
private void GroupBoxRequestTypeCheckedChange(object pSender, EventArgs pEventArgs)
{
HelperClass.HandleGroupBoxRequestTypeCheckedChanged(pSender, pEventArgs, this);
}
Where 'this' is the Form itself which has all the references to the objects I need to manipulate?
It's probably worth noting that I've learned a good bit about the Cross-Thread calls and I've started making Extension methods for many instances that I need which are simplistic.
Another question - I notice that the Visual Designer automatically makes all Components created with it private by default, is it in general a bad idea to make these internal and use the form object to reference these components as needed from outside the class? If it is not a good idea, what is better?
First I would suggest to separate independent user-interface parts into UserControls or Components. Then - if needed - wire them using Events (eg. your own specialized events and properties.
For example you can place your main content (the TabControl / Container) in a UserControl and place that user control in the main form. All tab-/page-switching logic/UI etc. then belongs to that user control. In that UserControl you can define for example your own Event that gets fired when the user switches a tab. The main form then can register to this event - just like it can for other Winforms-control-events - and do its stuff (eg. change the window title to represent the currently active tab).
Then next you can move the content of each tab to its own user-control and use these user-controls within your new tabs-usercontrol. Move the logic down to the UserControl which is responsible for the given task.
A form/controls hierarchy from some typical application could look like this:
MainForm (Form)
MainTabContainerControl (UserControl)
Page1Control (UserControl)
Page2Control (UserControl)
MyImprovedDbRowGridControl (UserControl or Component)
Page3Control (UserControl)
SidebarControl (UserControl)
SearchControl (UserControl)
MyImprovedDbRowGridControl (UserControl or Component)
QuickHelpControl (UserControl)
Next thing is so keep all the UI-eventhandlers as small as possible and doing only UI stuff. Move other logic like business- or dataaccess-logic to other classes outside of the user-interface.
If you have combinations of the controls that are needed more then once in the application: move them to a re-usable UserControl. (eg. breadcrum).
Regarding your sample code you can make it more compact and therefore maintainable by simplyfing its logic:
if (this.fSelectedButton.Equals(this.RadioButton_Delete))
{
this.TextBox_DestinationFile.Enabled = false;
this.Button_DestinationBrowse.Enabled = false;
}
else
{
this.TextBox_DestinationFile.Enabled = true;
this.Button_DestinationBrowse.Enabled = true;
}
...could be:
var delete = fSelectedButton == RadioButton_Delete;
this.TextBox_DestinationFile.Enabled = !delete;
this.Button_DestinationBrowse.Enabled = !delete;
Update:
When it comes to refactoring and code-cleanup a very usefull tool is Resharper (R#). I can highly recommend it.
Hope this gives you some ideas where to start.
I am trying to create a reusable function that can open a single instance of form. Means if a form is not already open it should create and show the new form and if already open it should bring the existing form to front.
I was using the following function,
if (Application.OpenForms["FPSStorageDemo"] == null)
{
FPSStorageDemo fp = new FPSStorageDemo();
fp.Name = "FPSStorageDemo";
fp.Show();
}
else
{
((FPSStorageDemo)Application.OpenForms["FPSStorageDemo"]).BringToFront();
}
But I have to write this code again and again whereever I have to open a form. But I need a single reusable function that can do this job.
I wrote a function like,
void OpenSingleInstanceForm(Type TypeOfControlToOpen)
{
bool IsFormOpen = false;
foreach (Form fm in Application.OpenForms)
{
if (fm.GetType() == TypeOfControlToOpen)
{
IsFormOpen = true;
fm.BringToFront();
break;
}
}
if (!IsFormOpen)
{
Object obj = Activator.CreateInstance(TypeOfControlToOpen);
//obj.Show(); //Here is the problem
}
}
But at the end I don't know how to show the new form instance. Can anybody suggest how to do it? Is this wrong or there is another way to do this?
Thanks in advance.
public static class FormUtility
{
public static FormType GetInstance<FormType>() where FormType : Form, new()
{
FormType output = Application.OpenForms.OfType<FormType>().FirstOrDefault();
if(output == null)
{
output = new FormType();
}
//you could add the show/bring to front here if you wanted to, or have the more general method
//that just gives a form that you can do whatever you want with (or have one of each).
return output;
}
}
//elsewhere
FormUtility.GetInstance<Form1>.BringToFront();
I'd also like to take the time to mention that while having methods like this are quick and easy to use, in most cases they are not good design. It leads you to the practice of just accessing forms globally rather than ensuring that when forms need to communicate with each other they do so by exposing the appropriate information through the appropriate scope. It makes programs easier to maintain, understand, extend, increases reusability, etc. If you have trouble determining how best for two or more forms to communicate without resorting to public static references to your forms (which is exactly what Application.OpenForms is) then you should feel free to post that question here for us to help you solve.
You are looking for Singleton
Check this Implementing Singleton in C#
I am using C# and a very old version of .Net. I have hundreds of forms and a class. Each form has a ProcessDump() method. When a form is opened, its controls are passed to my class. I need to call ProcessDump method and all i have is controls of the form. How can I access to the method?
Have each form implement an interface called IProcessDump:
interface IProcessDump
{
void ProcessDump();
}
Assuming WinForms, there is the FindForm method going back to .NET 1.1. Grab the form and test it for the interface:
Form formRef = myControl.FindForm();
IProcessDump procDump = formRef as IProcessDump;
if (procDump != null)
{
procDump.ProcessDump();
}
Alternatively, controls have a Parent property. For controls placed directly on the form the parent will be the form:
foreach (Control c in myControls)
{
if (c.Parent != null && c.Parent is Form)
{
// Found, go nuts.
}
}
The null check might not be required.
I hope you can help me with this one. My application is monitoring a database for alerts. When a alert shows up in the database, my application will add it to the main form in a datagridview, and depending on its priority it will also create a small winform popup with the event.
In the datagridview is a button to flag the alert as "seen", it will then update the database and be it will be gone from the list. However the popup form for this event is still open.
Does anyone know how to close this form? I need a way to find a specific form between the possible multiple alert forms that are open.
The closest I have come this far is the following code:
private void closeForm(int id)
{
foreach (Form f in Application.OpenForms)
{
if (Convert.ToString(id) == f.Name)
{
this.Close();
}
}
}
Which works up until the point that it closes the correct form. then it gives an error saying "Collection was modified; enumeration operation may not execute." This kinda makes sense, but I simply can't figure out another way to do it.
I have a winform class called Alert, wich makes the new forms. As you can see they will get a standard text "Alarm" and a unique Name based on the alert ID.
Alert alertform = new Alert(id);
alertform.Name = formid;
alertform.Text = "Alarm";
alertform.Show();
I hope someone has some good ideas how I can go about this. I have searched but cannot realy find a simple and elegant way to do this.
You need to add break; to your loop after you close the form. The collection is modified when you close the form (that form is removed from the collection), thus rendering the foreach loop invalid. And should you not be calling f.Close, rather than this.Close?
private void closeForm(int id)
{
foreach (Form f in Application.OpenForms)
if (Convert.ToString(id) == f.Name)
{
f.Close();
break;
}
}
You should simply be able to store a reference to your form in the DataGridView or its DataSource then close the form using that reference. This approach is less likely to break in the future than iterating over all the application forms.
What would probably work best is to add a hidden column to the DataGridView that holds the form id, then also have a Dictionary<int, Form> which you use to get the reference to the Form you want to close.
Then you can simply get the form reference out of the dictionary and call close on it:
private void CloseAlertForm(int id)
{
Form f = dict[id];
f.Close();
dict.Remove(id);
}
Additionally you could store Action delegates instead of form references allowing you to slightly decouple the alert forms and the grid form.
just get ref. from foreach loop and close the form outside it.
private void closeForm(int id)
{
Form formtoclose=null;
foreach (Form f in Application.OpenForms)
{
if (Convert.ToString(id) == f.Name)
{
formtoclose = f;
}
}
if(formtoclose!=null)
formtoclose.Close();
}
A Close modifies your OpenForms collection, so instead of enumeration over the OpenForms collection directly, you could enumerate over a copy.
LINQ is very handy into making copies, like this:
foreach (Form f in Application.OpenForms.Where(i => Convert.ToString(id) == i.Name).ToList()) {
// Save to close the form here
}
The ToList executes the query, and stores the copy.
var names = Application.OpenForms.Select(rs=>rs.name).ToList()
foreach (string name in names)
if (Convert.ToString(id) == name)
{
Application.OpenForms[name].Close();
}
You could use the type of the forms to find them (And ToArray to create a new collection an avoid changing the collection you are enumerating).
private void CloseAlerts()
{
var openForms = Application.OpenForms.Cast<Form>();
foreach (var f in openForms.Where(f => f is Alert).ToArray())
{
f.Close();
}
}
In this case you don't need to set a name :
Alert alertform = new Alert(id);
alertform.Text = "Alarm";
alertform.Show();