|
Hi,
I am trying to write a user control and I need to capture the arrow keys. The form I am testing on does not have KeyPreview on, but when my control has focus and I press the arrow keys it changes focus to the appropriate control on the form.
How can I capture the arrow keys?
After further investigation, if I press the key twice the control "sees" the keyboard press ???!!!!???
Thanks,
Richard
|
|
|
|
|
OK, I have a control, Foo. This class has an object, FooOptions, as a property (named Options). On FooOptions there is a integer property, Number.
I want to make FooOptions editable from the designer, when a Foo control is planted on a form. In particular, I want to pop up a dialog box when the user double-clicks on Options. So I wrote a form, FooOptionsUIEditor, which holds a PropertyGrid (which gets an instance of FooOptions), and gets launched from FooOptionsEditor, which is derived from UITypeEditor. I set the Editor attribute on the Foo.Options property. I also wrote FooOptionsSerializer, which is devired from CodeDomSerializer, and used that for FooOptions's DesignerSerializer attribute. Finally, on Foo.Options, I set the DesignerSerializationVisibility attribute to Content.
What this should do, I expect, is give me a form when I double click on Options in the designer, where I can edit Number. When I close the dialog, it should mark the parent form (which holds an instance of Foo) as editted, and allow me to Save, which would trigger the serializer and place some code in the Windows Forms Designer generated code area on said parent form.
And in fact, everything works-- except that the parent form is not getting marked as editted. My Foo.ShouldSerializeOptions() method is getting called (a lot), and I'm returning true. If I change some other property, either on Foo or on the parent form containing Foo, then the parent form is marked as editted, and I can save, and my serializer works perfectly. My changes are lost if I just edit the FooOptions and close the form in the designer. However, if I edit the FooOptions twice from the designer, the first changes show up, so it's persisted in memory alright.
I thought that maybe there was some trouble with the fact that I was editting FooOptions in a modal form, so I rewrote it to edit with a drop-down. That didn't work. I tested a drop-down with a simple string property on Foo, and that worked. So then I tested a simple string property on Foo, editted with a form, and that worked to. I have to conclude that the fact that FooOptions is an object is causing some kind of trouble.
Incidently, on Foo, Options only has a getter, no setter. But if I add a setter, the behavior doesn't seem to change.
How do I get the parent form to be marked as editted?
This is the first time I've worked with designers and customizing designer behavior, so please, any tips are welcome, no matter how simple. I've been banging my head against the wall for 3 days now.
|
|
|
|
|
object88 wrote:
This is the first time I've worked with designers and customizing designer behavior, so please, any tips are welcome, no matter how simple.
You've obviously done your research.
While it may not make a difference, be sure that you're calling GetService on the IServiceProvider instance passed to your UITypeEditor.EditValue override, and get the IWindowsFormsEditorService in order to call ShowDialog to open your form. That ensures that your dialog is parented properly with the designer and may trigger the results you're looking for. I haven't spent a lot of time in this area of the component designer IL (which you can view with ildasm.exe straight from the SDK, or use a decompiler like .NET Reflector), so I'm not totally sure.
Typically when you want to edit "sub-options", one would either extend ExpandableObjectConverter or just derive from TypeConverter and implement the GetProperties and GetPropertiesSupported . In this case - if you're using a struct - you'll also want to implement CreateInstance and GetCreateInstanceSupported so that you're struct gets recreated the CodeDomSerializer picks up the change.
I'm guess that in your case, such a simple option editor isn't desireable. It would seem that the problem is that the serializer isn't signaling to the designer host (VS.NET) that the file has changed. You may want to query for the IComponentChangeService (as you should with the IWindowsFormsEditorService as I mentioned above) and call OnComponentChanged with the necessary parameters when you're finished. This will signal the designer host that your component has changed (or perhaps that a single property has changed, depending on how you call OnComponentChanged ) and it should then serialize your code correctly.
The specially named ShouldSerializerPropertyNames are really for when non-default values are assigned to a property. It really wasn't designed for changes in the component model like this.
HTH
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Thanks for the quick reply. I am using the IWindowsFormEditorService retrieved from the passed-in provider in EditValue to display my dialog.
So if I extend ExpandableObjectConverter or derive from TypeConverter, I set that on my FooOptions class with the TypeConverter attribute? I didn't mention it before, but I actually have a class that does that, except only to override the "ConvertTo" method when requesting a string, so that I don't get the class name in the designer. I'll try toying with the GetProperties and GetPropertiesSupported methods.
Failing that, I'll check out the IComponentChangeService stuff. Seems like there's a wealth of service stuff in there that I haven't discovered yet.
I won't worry about ShouldSerializeXXX.
Thanks for the help! I'll be sure to report back when I find out anything.
|
|
|
|
|
WOOOOHOOOO!!! Calling IComponentChangeService.OnComponentChanging and .OnComponentChanged did the trick. After I make the changes in the designer, the changes in the code are immediately reflected in the generated code area. In my code, I just passed in null for the MemberDescriptor, oldValue, and newValue... is there any advantage to calling them out explicitely?
(As an aside, the TypeConverter stuff didn't do anything, but you suspected that. Alternately, I just didn't twiddle the right bits.)
Thanks you! This problem has been driving me farking nuts.
|
|
|
|
|
Glad to hear it!
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
In this case you're not really using the conversion methods to convert from one type to another, but to allow the designer (in this case, the PropertyGrid) to edit properties of your type and - for value types - to create a new instance in order to set those properties.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
This seems to work fine in a Windows Form application but fails in a Class Library, why?
My App.config says:
<configuration>
<appsettings>
<add key="hypSOAPMaxJobsPerMailer" value="10">
if I issue a ConfigurationSettings.AppSettings.HasKeys() in a Class Library it tells me FALSE, but in a windows form app it tells me TRUE!!?
What am I missing?
Guillermo Jimenez
|
|
|
|
|
Sorry, this is the content of the App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="hypSOAPMaxJobsPerMailer" value="10" />
</appSettings>
</configuration>
|
|
|
|
|
Because the executable loader only associates .config files for the AppDomain for applications (.exe), not libraries (.dll; this is documented). A library will use the settings specified for an application's .config file in which the library is loaded and mapped.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
hi, i have a drawing using GDI+ in a function Drawpicture(Graphics a) n I called it in
protected override void OnPaint(PaintEventArgs e)
{
Drawpicture(e.Graphics)
}
However, i want it to be on the picturebox. i tried calling it like this:
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Drawpicture(e.Graphics)
}
but it won't work. Plz help. thanks
Chris
|
|
|
|
|
When overriding OnEventName methods you should almost always call base.OnEventName name to make sure that the events gets fired. If you don't, even handlers are called and other operations that may be pertinent to the operation won't run (your override is called in lieu of the member you're overriding; the base member will not be called automatically).
nuttynibbles1984 wrote:
but it won't work. Plz help. thanks
You're going to have to be a little more clear than that. Are you getting exceptions? Is your method even being called (i.e., you should debug your code first)? Is it called but nothing appears?
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
hi, erm there are no error. currently i'm drawing it directly onto the form. i only draw it onto the form when i click a button.
//initially,set picturebox enable properties as false;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if(pictureBox.Enabled == true)
{
Drawpicture(e.Graphics);
}
}
private void Drawpicture(Graphics a)
{
Graphics myGraphics = CreateGraphics();
....
}
private void button2_Click(object sender, System.EventArgs e)
{
pictureBox.Enabled = true;
}
By doing this, i display my drawing onto the form when the button is click. However, i want to display it into the pictureBox when the button is click. How should i do that.
Chris
|
|
|
|
|
Maybe I'm reading this incorrectly but isn't this what you want:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if(pictureBox.Enabled == true)
{
pictureBox.Image = CreateGraphics();
}
}
|
|
|
|
|
I would make a custom PictureBox by inheriting a new class from PictureBox and giving it an override to its OnPaint method.
In the constructor for your new PictureBox inheritor you make these calls:
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.DoubleBuffer, true);
I understand these enable the control to draw itself in an efficient manner. Hope that helps. Please try to be more specific and plz is not a word.
vir·tu·al re·al·i·ty
n. Abbr. VR
A computer simulation of a real or imaginary universe in which Microsoft APIs are thoroughly documented and behave in an entirely logical manner.
|
|
|
|
|
hi, currently i'm drawing it directly onto the form. i only draw it onto the form when i click a button.
//initially,set picturebox enable properties as false;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if(pictureBox.Enabled == true)
{
Drawpicture(e.Graphics);
}
}
private void Drawpicture(Graphics a)
{
Graphics myGraphics = CreateGraphics();
....
}
private void button2_Click(object sender, System.EventArgs e)
{
pictureBox.Enabled = true;
}
By doing this, i display my drawing onto the form when the button is click. However, i want to display it into the pictureBox when the button is click. How should i do that.
Chris
|
|
|
|
|
If you want to draw on the PictureBox , then you can't draw on the Form . The painting operation has to occur for the control on which you're actually painting.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hi,
my problem is the following: I have a class called MyClass. A second class MyDerivedClass is derived from MyClass. A third class MyTwoTimesDerivedClass is derived from MyDerivedClass. Now I have some public variables and Methods in MyClass, which I want to use in MyDerivedClass. But I don't want them to be part of MyTwoTimesDerivedClass. How can I prevent them from being derived further?
Thanks,
Benjamin
|
|
|
|
|
That indicates there's a fundamental problem in your OO design that you may want to consider changing. Derivative child classes are supposed to inherit or override functionality from their parent classes. That's what polymorphism is all about (well, about the overriding, mostly).
You could defined the members as virtual in MyClass and override them in MyTwoTimesDerivedClass , only to throw a NotImplementedException or NotSupportedException . Furthermore, you can hide these from both the component designer and source code editor using the appropriate attributes like so:
[
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public override void BaseMethod()
{
throw new NotImplementedException();
} That will hide them, but you can't "undefine" an inheritted member.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
You mark a method in MyDerivedClass "sealed" which would mean MyTwoTimesDerivedClass cannot override it, but that doesnt hide it from them as stated in the post above.
public class MyClass
{
public virtual void DoSomething(){}
}
public class MyDerivedClass : MyClass
{
public override sealed DoSomething(){}
}
public class MyTwoTimesDerivedClass : MyDerivedClass
{
}
|
|
|
|
|
1. Post a reply to the parent post, not mine. You're replying to him. I know very well what the sealed keyword does.
2. That's not actually what he asked. The original post was about "un-inheritting" methods from a base class. Yes, sealed may be a good idea to use so derivative classes couldn't override and re-implement the methods, but - as I mentioned - the fundamental flaw is with his OO design. He shouldn't extend classes if he absolutely does not want to inherit their functionality. All you can do in these cases is hide members and either get/set/return the base class's member value or throw an exception. This is actually done in many places throughout the Windows Forms classes in the BCL, but only because the class members don't make sense in some cases (not to stop you from using them).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Hello,
I have a little problem. Maybe someone here can help me.
The problem is: My program (written in C# .NET) calls a COM-Server. This Server works a little bit and then he sent me the Results back in a callback-method. This method is open by the COM-Server in a new Thread. So far so god.
After I became this results I have to sent the next command to the server. But before I can sent a new command, I have to release the complete callback-method from the COM-Server. But I can’t close this method before sending the new command.
At the moment I open a new Tread in this callback-method. This new Thread sent the new command after the old Thread closed. But sometimes the old Thread closed not so fast and then it crashes.
Is there a any standard way to solve this Problem?
Can someone help me?
Sorry for my English
David
|
|
|
|
|
What's the threading model of the COM server?
If you're objective is to send the next command back to the server in the first thread (the thread on which your proxy was instantiated), then you need to invoke a method on that thread. If you're calling methods on your proxy from a Windows Forms control or form, you can use Control.Invoke . The Framework handles calling the method on the thread on which the control was created if you call it right. For example:
delegate void SendCommandHandler(string command);
void SendCommand(string command)
{
}
void Callback()
{
if (InvokeRequired)
{
SendCommandHandler d = new SendCommandHandler(SendCommand);
Invoke(d, new object[] {"DO SOMETHING"});
}
else SendCommand("DO SOMETHING");
}
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
At first: Tanks for this Information,
The COM-Server is a STA Server but I can use only one Apartment at the same time, because the Server needs very mutch Performance.
So the problem is not to start a new Thread. (The invoke command is very nice) At the moment I sent the next command in a other Tread too, but it starts like this:
SentCommand wrapper=new SentCommand(Thread.CurrentThread,myobject);<br />
ThreadStart ts=new ThreadStart(wrapper.SentNewCommand);<br />
Thread SecondThread = new Thread(ts);<br />
SecondThread.Start();
The real Problem is the speed of the second Thread. When I start the second Thread from the Callback-Tread both Thread exist at the same Time. So if the Second Thread is too fast and sent the new command before the Callback-tread is closed -> it crashes. So I think its not important if the Second-Thread is a new one or a existing GUI-Tread (Control).
I tried to synchronise this 2 Treads like this:
if (CallbackThread != null) <br />
{<br />
if (CallbackThread.IsAlive)<br />
{<br />
CallbackThread.Abort();<br />
}<br />
}
but it doesn’t work.
|
|
|
|
|
What you're doing isn't synchronizing thread access - you need locks for that. The C# lock statement does just that. Define a static object initialized to an instance of something. In your case, you could also synchronize against this since your .NET component is running in an apartment.
The lock uses a Monitor . There's also Mutex and various events you can signal. I suggest you read through the documentation for the namespace members in System.Threading . There's a lot of ways you can correctly synchronize thread access.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Sustained Engineering
Microsoft
[My Articles] [My Blog]
|
|
|
|
|