Charles Jenkins a écrit :
I am using the .NET Compact Framework, which seems to be designed for
frustration, becaue the method you NEED is never available. For
instance, MenuItem.PerformClick() does not exist in the Compact Framework.
I must admit I never used the Compact Framework. PerformClick seems to
be available for buttons, but not for menu items in this world :-(
<snip>
Because the VS 2005 designer is not reliable for custom controls, I am
trying to put plain old controls (with no visual inheritance) onto my
forms, then add the behaviors I need at runtime. I need
ClickableMenuItem to inherit from MenuItem so that it can call
OnClick(); but I need each new ClickableMenuItem to get its state from
the MenuItem that is actually available. I want to be able to do
something like this:
// Use what we have to create what we actually need
ClickableMenuItem cmi = new ClickableMenuItem( menuItem );
cmi.DoClick();
Well, except with Delphi, I have always been disappointed with
designers. The code they ususally produce is such a mess that they end
up being unable to deal with it after a while...
I think this would require the kind of inheritance that would lead me to
have problems with the designer. In order to add ClickableMenuItems
using the designer, I would have to create a ClickableContextMenu, right?
I do not think so, as with inheritance a ClickableMenuItem would be a
MenuItem. That reminds me of a hack I have used with VS2003 that should
work with VS2005 : add a MenuItem to your menu vie the designer, save
your files, close the designer, and replace MenuItem with
ClickableMenuItem directly in the source code for your instance (ther
should be only two occurrences : one in the variable declaration, one in
the method InitializeComponents). Reopen the designer : you are done !
These workarounds still require me to make the ClickableMenuItem to get
its state (fields and event handlers) from the MenuItem I want to
impersonate. That leads me back to this question. Given that I cannot
say "this = that," how do I copy all the MenuItem's fields and events
from the MenuItem I have into the ClickableMenuItem that I want?
The first method uses inheritance : you are just not using the designer
for your specific components.
Oddly enough, I really *did* attempt to combine inheritance and
composition, just like you guessed, in the hope that an inherited
control could gain access to the protected methods of the member
control's instance---
class ClickableMenuItem : MenuItem {
private MenuItem m_mi;
public ClickableMenuItem( MenuItem mi ) {
m_mi = mi;
}
public void DoClick( EventArgs e ) {
m_mi.OnClick( e );
}
}
I have been there before : no matter what you are trying to achieve,
inheritance cannot live with composition (wit the same class involved,
of course ;-). It is always wrong.
But here is your real point : how to simulate the click ? Be careful
that OnClick just triggers the handlers registered to the Click event,
it does not perform any MenuItem specific action associated with the
click... The best solution if you want to call OnClick anyway is to use
inheritance and just :
public void PerformClick() {
this.OnClick(new EventArgs());
}
What if OnClick is not enough ?... I would try to use a reflector to
look deep into the MenuItem class (you can find one there :
http://www.aisto.com/roeder/dotnet/), and look for a private method that
would look like a PerformClick. Then I would call it using reflection,
which is a secret way to bypass the laws of method accessibility
(beuaark)...
Last thougt : I think that if you really had separated UI code from the
rest, you would not have felt this need to call a method that does not
exist... Let me explain that : what I think you did is something that is
very usual thanks to designers, I mean add a handler to your MenuItem,
and perform your actual actions in there
public void MyForm_myMenuItem_Click(object sender, EventArgs e) {
// related actions...
}
So now you will want to programmatically click the myMenuItem to
perform the actions... Try instead to separate the code related to your
actions in another layer (most likely in another class)
public void RelatedActions()
{
// some code here
}
and just replace the preceding with :
public void MyForm_myMenuItem_Click(object sender, EventArgs e) {
RelatedActions();
}
Now, can you not try to call RelatedActions directly instead of trying
to click the menu ?