|
googling around i found some extension to the default tiempicker to make backcolor suitable...what i have till now is:
namespace primoAlpha {
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Security::Permissions;
public ref class extendedDateTimePicker : DateTimePicker
{
private:
Color _BackColor;
public:
property Color BackColor
{
virtual Color get() override {
return _BackColor;
}
virtual void set(Color value) override {
_BackColor = value;
Invalidate();
}
}
protected:
[SecurityPermission(SecurityAction::Demand, Flags=SecurityPermissionFlag::UnmanagedCode)]
virtual void WndProc( Message% m ) override
{
if ( m.Msg == (int) 0x0014 ) {
Graphics ^g = Graphics::FromHdc(m.WParam);
g->FillRectangle(gcnew SolidBrush(_BackColor),
ClientRectangle);
g->ReleaseHdc();
return;
}
WndProc(m);
}
};
}
the code compile with no error but when i run it gives me an
"An unhandled exception of type 'System.StackOverflowException' occurred in primoAlpha.exe"
any help is really apprecieted, i'm a noob in c++
|
|
|
|
|
Hi,
IMO your WndProc is calling itself instead of the base WndProc method. I don't know the correct C++/CLI syntax for it though.
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
the code from which i constrcuted the code tell to use
Form::WndProc(m);
but if try to use it it tell me "candidate function(s) not accessible"
cause Form::WndProc is a private code.
|
|
|
|
|
it works in C#:
public class extendedDateTimePicker : DateTimePicker {
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
}
}
BTW: the message parameter takes a reference.
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Luc Pattyn wrote: the message parameter takes a reference.
Do you have any idea why it is passed as reference?
|
|
|
|
|
the message is a struct you may want to modify and pass on.
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Ahh. That was simple. I was not aware that Message is a struct.
Thanks
|
|
|
|
|
With the number of messages flying around in Windows, they'd better be structs.
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Correct syntax is BaseClassName::MethodName . So you write DateTimePicker::WndProc(m) .
public ref class extendedDateTimePicker : DateTimePicker
{
protected:
[SecurityPermission(SecurityAction::Demand, Flags=SecurityPermissionFlag::UnmanagedCode)]
virtual void WndProc( Message% m ) override
{
if ( m.Msg == (int) 0x0014 ) { }
DateTimePicker::WndProc(m);
}
};
|
|
|
|
|
antd the winner is "N a v a n e e t h" ...thank you man...you pointed out the problem...still i'm wondering why i didn't get it by my self
|
|
|
|
|
Winner should be Luc as he pointed out the problem. I am just a syntax provider.
modified on Monday, September 28, 2009 10:22 AM
|
|
|
|
|
yes...but i know only c++ and base for me before today was an unknown identifier... now i know it's a pointer to the "base class" from which i derive mine
|
|
|
|
|
I have a background worker thread which I run to analyse some data the results of which I want to dipslay in the GUI. My question is how do I inform the main GUI thread that the worker thread has finished (the data is ready) so that it can update the GUI. I do not want to pause the main GUI thread to wait for the worker thread.
The only method I know (used back before Managed C++/CLI) is to send a windows message from the worker thread. This is handled in the message loop of the main GUI thread and so the GUI can be updated. However this feels a bit clunky to me and can cause problems when a dialog is open and the windows message is handled in the dialog's message loop and not that of the main application.
Does anybody know of a better method?
|
|
|
|
|
LetsMond wrote: how do I inform the main GUI thread that the worker thread has finished (the data is ready) so that it can update the GUI
Once done, call a method that updates GUI thread. Only thing to take care is to use Invoke/BeginInvoke. Here is a sample code.
MethodInvoker^ method = gcnew MethodInvoker(this, &YourForm::UpdateUI);
this->BeginInvoke(method); This sends a message to the main thread's message loop. You can update the controls inside the method UpdateUI .
MethodInvoker is delegate supplied with .NET framework. If you want to pass additional arguments to method, you may need to create your own delegates.
LetsMond wrote: The only method I know (used back before Managed C++/CLI) is to send a windows message from the worker thread. This is handled in the message loop of the main GUI thread and so the GUI can be updated.
This is the correct method. Message sending is encapsulated inside Invoke or BeginInvoke methods. These methods calls win32 SendMessage and PostMessage .
|
|
|
|
|
Thanks. This will do what I need.
|
|
|
|
|
Good to hear that it helped.
If you are interested, another possible method to do cross thread communication is to use SynchronizationContext[^] class. This will do the marshaling and provide a neat way for cross-thread communication.
Here is a sample code.
SynchronizationContext^ context = SynchronizationContext::Current;
Thread^ t = gcnew Thread(gcnew ParameterizedThreadStart(this, &YourForm::Execute));
t->Start(context);
void Execute(Object^ obj)
{
SynchronizationContext^ context = dynamic_cast<SynchronizationContext^>(obj);
context->Post(gcnew SendOrPostCallback(this, &YourForm::UpdateUI), "Sample text");
}
void UpdateUI(Object^ obj)
{
}
|
|
|
|
|
LetsMond wrote: However this feels a bit clunky to me and can cause problems when a dialog is open and the windows message is handled in the dialog's message loop and not that of the main application.
I didn't get that fully.
Are you saying the updates will not be visible when you have a modal window shown? If yes, that shouldn't be a problem. You will see updates happening to parent form even if a modal windows is shown.
|
|
|
|
|
You can also use a BackgroundWorker . Set the DoWork event to be your worker method, and the WorkerCompleted event to be the method that updates your GUI. I believe the WorkerCompleted event executes on the thread that started the worker thread (which in most cases will be your GUI thread).
Dybs
|
|
|
|
|
dybs wrote: I believe the WorkerCompleted event executes on the thread that started the worker thread
Nope.
Both the ProgressChanged and RunWorkerCompleted event handler will execute on the main (aka GUI) thread, no matter which thread created or started the BackgroundWorker instance. So they basically execute a MainForm.Invoke() for you.
Luc Pattyn
Have a look at my entry for the lean-and-mean competition; please provide comments, feedback, discussion, and don’t forget to vote for it! Thank you.
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Thanks for the clarification. I've always been starting a BackgroundWorker from the GUI thread anyway, so I haven't actually tested which thread the WorkerComplete event ran on. Good to know.
Dybs
|
|
|
|
|
Looks like I started a big thread discussion with that question!
I actually ended up using the BackgroundWorker class to solve my problem; however I'm having a slight problem with it. My WorkerComplete event is not always being called from the main GUI thread. I have 4 threads now which use a base class to handle the management of a BackgroundWorker object and then override functions for DoWork and WorkerComplete. In 2 cases the WorkerComplete call comes from the main GUI thread and in the other 2 cases it comes from a completely different worker thread. I'm a bit confused by this as the same code is used to create and start the BackgroundWorker in all 4 cases.
Does anybody have any ideas as to what might cause the WorkerComplete event to be called from a worker thread and not the main GUI thread?
|
|
|
|
|
LetsMond wrote: My WorkerComplete event is not always being called from the main GUI thread
I doubt that very much. what makes you think so?
I suggest you check by logging the value of Thread.CurrentThread.ManagedThreadId
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
I'm looking in the "Threads" Window to see which thread I'm on when I hit a breakpoint in the RunWorkerCompleted function. In the 2 bad cases I can see that it's not on the main thread (which is helpfully shown in green). Also if I then go on to try and perform a GUI operation things go horribly wrong.
|
|
|
|
|
Hi,
I ran some tests and there seems to be something wrong with BackgroundWorkers.
Contrary to what the documentation says, it seems like the (ProgressChanged and) RunWorkerCompleted event only executes on the GUI thread if the BGW was created (or got started?) on the GUI thread.
My investigation continues...
Luc Pattyn
Local announcement (Antwerp region): Lange Wapper? Neen!
|
|
|
|
|
Thanks for investigating!
I've been looking into the issue and I think I've found the problem, if not a good solution. When the BackgroundWorker doesn't work correctly I have created, displayed and closed a Form before starting the thread. The From changes the current SynchronizationContext object to its own thread. This becomes invalid after the Form closes (it doesn’t change it back to the original SynchronizationContext) and causes the strange behaviour when the BackgroundWorker is used.
The reason I'm seeing this might be because (for various unchangeable reasons) my program is an MFC App which also uses CLI.
I have no idea how to solve the problem. Yet
|
|
|
|