|
Thanks, the problem with that ( I think ) is that the value of the ToolStripMenuItem could be changed subsequently by another open MdiChild form.
One way that I can get half of what I need is to have a public static variable in a static class ( say my starting code ) which I can access from all of my forms. I can then set the value of this to the value of the ToolStripMenuItem.Checked property in the CheckedChanged event handler for the ToolStripMenuItem.
I can then check ToolStripMenuItem.Checked for a certain condition from any child form.
But.... how can I Set the ToolStripMenuItem.Checked property in code?
It may help if I give a better example of what I want to do.
In MainForm ( the MdiParent form ) I have a confirmDeletesToolStripMenuItem with CheckOnClick set to True.
In any child form, during the delete process, if MainForm confirmDeletesToolStripMenuItem.Checked == True; then they will get a Confirm Deletes Message Box or not if False.
In the Confirm Deletes Message Box I will also have a CheckBox option "Do not show again for this session" that if checked will Set the MainForm confirmDeletesToolStripMenuItem.Checked = False; .
I guess I can also use Application Settings and set this type of thing in an Options form rather than on a Checked ToolStripMenuItem, however I'm sure there will be other reasons Get/Set the value of the Parent form from Child?
|
|
|
|
|
Along with storing checked status in configuration file there are other options also available, like..
Make one class and in that define one property which holds the value of ToolStripMenuItem,
and pass the object of this class between the forms(mdi and child form) whenever you required
the value of ToolStripMenuItem.
And also you need to update the value of the class property whenever the change occurs in value
of ToolStripMenuItem.
HTH
Jinal Desai - LIVE
Experience is mother of sage....
|
|
|
|
|
This method also ties the second form to the first one forever. You could never use the second form indepentaly of the first. This is bad design...
|
|
|
|
|
I would do it in a slightly long winded way, but it's far more flexible/extendable in future.
All child forms that need this functionality should raise an event to signal to the parent that it wants to update it's menu. The children should never have access to the menu directly! The best way to do this is to have a enumeration of menu items that you can add to as required.
namespace YourMdiApp
{
public enum UpdatableMenuItem
{
File,
Exit,
View,
}
}
Now you can create a class to pass as an argument with the event that details the item and the change required.
using System;
namespace YourMdiApp
{
public delegate void UpdateMenuItemEventHandler(object sender, UpdateMenuItemEventArgs e);
public class UpdateMenuItemEventArgs : EventArgs
{
private bool itemChecked;
private bool enabled;
private UpdatableMenuItem item;
private bool visible;
public UpdateMenuItemEventArgs(UpdatableMenuItem item, bool itemChecked, bool enabled, bool visible)
{
this.item = item;
this.itemChecked = itemChecked;
this.enabled = enabled;
this.visible = visible;
}
public bool Checked
{
get { return itemChecked; }
}
public bool Enabled
{
get { return enabled; }
}
public UpdatableMenuItem Item
{
get { return item; }
}
public bool Visible
{
get { return visible; }
}
}
}
Now you need a base class that all your child forms can derive from that has the event and methods to raise it
using System.Windows.Forms;
namespace YourMdiApp
{
public class FormChildBase : Form
{
public event UpdateMenuItemEventHandler UpdateMenuItem;
protected virtual void OnUpdateMenuItem(UpdateMenuItemEventArgs e)
{
UpdateMenuItemEventHandler eh = UpdateMenuItem;
if (eh != null)
eh(this, e);
}
public void PerformUpdateMenuItem(UpdatableMenuItem item, bool itemChecked, bool enabled, bool visible)
{
OnUpdateMenuItem(new UpdateMenuItemEventArgs(item, itemChecked, enabled, visible));
}
}
}
With this done, change your child forms to derive from FormChildBase instead of Form and call PerformUpdate when required.
using System;
namespace YourMdiApp
{
public partial class FormChildA : FormChildBase
{
public FormChildA()
{
InitializeComponent();
Click += new EventHandler(FormChildA_Click);
}
void FormChildA_Click(object sender, EventArgs e)
{
PerformUpdateMenuItem(UpdatableMenuItem.File, false, false, true);
}
}
}
All that's left to do is subscribe to the child's UpdateMenuItem event from the parent and update the menu accordingly - for example...
using System.Windows.Forms;
namespace YourMdiApp
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
FormChildA formChildA = new FormChildA();
formChildA.UpdateMenuItem += new UpdateMenuItemEventHandler(formChildA_UpdateMenuItem);
formChildA.MdiParent = this;
formChildA.Show();
}
void formChildA_UpdateMenuItem(object sender, UpdateMenuItemEventArgs e)
{
ToolStripMenuItem item = null;
switch (e.Item)
{
case UpdatableMenuItem.File:
item = fileToolStripMenuItem;
break;
}
if (item != null)
{
item.Checked = e.Checked;
item.Enabled = e.Enabled;
item.Visible = e.Visible;
}
}
}
}
Edit: Better still, you could keep a dictionary that maps UpdatableMenuItem s to the actual menu items so FormMain becomes...
using System.Collections.Generic;
using System.Windows.Forms;
namespace YourMdiApp
{
public partial class FormMain : Form
{
private Dictionary<UpdatableMenuItem, ToolStripMenuItem> menuItemDictionary;
public FormMain()
{
InitializeComponent();
menuItemDictionary = new Dictionary<UpdatableMenuItem, ToolStripMenuItem>()
{
{ UpdatableMenuItem.File, fileToolStripMenuItem }
};
FormChildA formChildA = new FormChildA();
formChildA.UpdateMenuItem += new UpdateMenuItemEventHandler(formChildA_UpdateMenuItem);
formChildA.MdiParent = this;
formChildA.Show();
}
void formChildA_UpdateMenuItem(object sender, UpdateMenuItemEventArgs e)
{
ToolStripMenuItem item;
if (menuItemDictionary.TryGetValue(e.Item, out item))
{
item.Checked = e.Checked;
item.Enabled = e.Enabled;
item.Visible = e.Visible;
}
}
}
}
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
modified on Thursday, July 15, 2010 7:02 AM
|
|
|
|
|
Thanks, there is a lot to absorb here ( for me anyway ) so I will work my way through it.
I'm sure I will be wiser when I understand it completely.
I have been struggling with fully understanding the concept of delegates, so this will prompt me to get a handle on that first.
|
|
|
|
|
AussieLew wrote: Thanks
You're welcome
AussieLew wrote: I have been struggling with fully understanding the concept of delegates, so this will prompt me to get a handle on that first.
Work through this article[^], it goes step by step. I wrote it for people exactly in your position.
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
Thanks Dave, I can see how using an event is the better way for the child form to cause a change in the parent form. Your article on events etc has helped clarify delegates etc to a great extent. Anything I'm missing I'm sure will "click" soon!
The second part of my question regarded getting the state of the ToolStripMenuItem on the MainForm
from the child form. So for example, if the MainForm ToolStripMenuItemConfirmDeletes item is Checked or not I can take the appropriate action when deleting a record on the child form.
The only way I can see is to have a static variable (say in the startup code Static Class)
bool confirmDeletes that is set whenever the MainForm ToolStripMenuItemConfirmDeletes.Checked property changes. This is accessible from all child forms and the MainForm as eg. Program.confirmDeletes
Can ( and should ) this be done via an event or is using a Static variable acceptable practice?
Lew
|
|
|
|
|
Glad it's helped
Good questions. Static variables/properties are almost never the correct way to go, that normally indicates a bad design. There are 3 methods that can be used. In order of easiest to most complex but also worst to best (as is often the case in programming!)
- Easiest but normally worst
Static properties/variables as you mentioned. If using this, as they will need to be either internal or public I would strongly suggest properties with a private backing field. - Next best
A singleton class instance. See here[^] for a good tutorial by one of the C# gods. - Normally the best, but can be complex to implement depending on class hierachys
Let the parent form decide if the delete should be allowed and perform it. The children simply request the action and pass any required data via an event.
Not everyone would agree, and the 2nd method is very commonly used in production code as it gives better separation than the 3rd which is good OOP practice and therefore often the better solution.
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
Thanks once again!
I will try your option 3 I think.
I have spent a lot of time getting one Form right with data validation and save, edit delete actions etc.
I have a few forms along similar lines to come yet. My next task was to simplify creation of these additional forms.
By having the child form pass the parent form data through events and having the parent form look after some of the actions, like add, edit, delete, save etc this would be some things that would not have to be duplicated in each form.
This is starting to get off topic now but I guess for similar forms with different data sources etc I should set up a form with a constructor that takes the parameters I want to change, plus events etc for form interaction, and use that as a basis for all my similar forms.
Lew
|
|
|
|
|
Yep - you're getting there and thinking along the right lines now!
The next problem you may come across is getting the result of the action request back to the child. There are two good methods for this.
1. You can have a property in your event args that the main (parent) from sets. This is the normally recommended method.
2. Sometimes a more intuitive way is to forget about the standard event signature and create your own delegate that actually returns a result. I've knocked up this quick sample to demonstrate.
using System.Windows.Forms;
namespace CpDelegateSample
{
public partial class FormMain : Form
{
private bool toggle;
public FormMain()
{
InitializeComponent();
toggle = false;
FormSub formSub = new FormSub();
formSub.DeleteRequest += new FormSub.DeleteRequestEventHandler(formSub_DeleteRequest);
formSub.Show();
}
private bool formSub_DeleteRequest(string data)
{
bool result = toggle;
string message = result ? "Allowing" : "Denying";
MessageBox.Show(string.Format("{0} {1}", message, data));
toggle = !toggle;
return result;
}
}
}
using System;
using System.Windows.Forms;
namespace CpDelegateSample
{
public partial class FormSub : Form
{
public delegate bool DeleteRequestEventHandler(string data);
public event DeleteRequestEventHandler DeleteRequest;
public FormSub()
{
InitializeComponent();
Click += new EventHandler(FormSub_Click);
}
void FormSub_Click(object sender, EventArgs e)
{
OnDeleteRequest("ABC");
OnDeleteRequest("DEF");
}
protected virtual void OnDeleteRequest(string data)
{
DeleteRequestEventHandler eh = DeleteRequest;
if (eh != null)
{
bool result = eh(data);
string message = result ? "Allowed" : "Denied";
MessageBox.Show(string.Format("{0} {1}", message, data));
}
}
}
}
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
I remember reading an article that said that List.Sort() was not necessarily reliable, but I cannot remember the context..
Does anyone know the reference or know of a sample (extra credit) that I can look at?
I believe it was someones example of a "better" sorting algorithm...
Thanks in advance.
I'd blame it on the Brain farts.. But let's be honest, it really is more like a Methane factory between my ears some days then it is anything else...
|
|
|
|
|
MSDN says List.Sort uses Array.Sort which is a QuickSort implementation.
unreliable? if it does not sort correctly or in a finite time, it is not an algorithm and not worthy to be part of .NET
unstable? correct (confirmed by http://en.wikipedia.org/wiki/Quicksort[^]). I hope you know what it means.
|
|
|
|
|
Learn something new every day.
BTW, 10^6 seconds is a finite amount. O(n)=n^2 can be scary on large sets.
|
|
|
|
|
Ennis Ray Lynch, Jr. wrote: Learn something new every day.
Same here. I've used the List.Sort() method for years but I've never had any trouble with it. Maybe because I only use List<> for small collections only.
The mind is like a parachute. It doesn’t work unless it’s open.
|
|
|
|
|
Do you have an alternative that you use?
The mind is like a parachute. It doesn’t work unless it’s open.
|
|
|
|
|
Most of the time I don't collect millions of objects, and I use the built-in Sort method. When it is really important, I apply special data structures and keep the "collection" sorted while building it up. Think of a list of lists, so items can be added to the right sub-list straight away.
I trust others will suggest you keep huge amounts of data in a database and rely on its sorting capabilities.
|
|
|
|
|
As you've been told, the sort method isn't really suitable on large data sets. It's important to understand that this is really the wrong place to apply sorting on large data sets - assuming it's coming from a database then the best way to do this is to retrieve the data already sorted and then fill the list.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
How do I format Column when a Gridview loads?
Details:
I have a grid named : SubcategoryGrid
the grid is binded to a data binding source.
there is a column in that grid(double type), I need to apply a simple conversion formula after the data binding completes
what gridview argument do I use? or how would I go on about this?
|
|
|
|
|
Hi,
have a look at the CellFormatting event. You could watch the value (e.Value) to be displayed and:
1. modify it,
2. or apply a special formatting (dgv.Columns[COL].DefaultCellStyle.Format="#,###";),
3. or set a special backcolor (e.CellStyle.BackColor=Color.Yellow; however this does not work for empty cells!).
I have used some of the above in my CP Vanity[^] article.
|
|
|
|
|
Thanks,
this is what I have:
Class:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
}
What args do I use in designer??
I tried this event to trigger cellformating:
this.SubcategoryGrid.DataBindings += ........
|
|
|
|
|
AFAIK there are two distinct mechanisms, one to provide the data (databinding), one to display the data (formatting).
The binding is whatever you want it to be.
The formatting will fire the CellFormatting event if you wire it up, which you can do by double-clicking the event in the events list, or by adding a dataGridView1.CellFormatting+=dataGridView1_CellFormatting; statement in the form's constructor. As you already have the outline, you probably have done the former already.
Now start manipulating the current cell inside your event handler, any way you want (You did not specify what kind of "simple conversion formula" you want).
|
|
|
|
|
Cellformating worked.
Thank you!
|
|
|
|
|
Why does it have to happen after the binding?
Is there some reason you can't use DataFormatString[^]?
|
|
|
|
|
That is for a WebUI thingy, isn't it? I believe the OP wants a WinForm with a DataGridView.
|
|
|
|
|
|