Hello,
I just created a docker in visual studio.
I have attached something with Page.Properties that displays in docker.
but how can i refresh docker when user change page in coreldraw.
I have find document.pagechange or pageactivate event but don't know how to use.
please guide me.
I found a way to add all VBE interface methods to application VBE...
No after some tests I am almost sure that unsubscribing of pagheChange event is a Corel problem... I created a bool variable made true when subscribing and false when unsubscribing. So nothing from inside code unsubscribe the event. Corel itself looks to be guilty for this instability...
That's why the necessity of obtaining the event handler following it and resubscribing in case of null is even bigger if you really need this events working smooth...
Can anybody help on this issue? At least with a piece of idea or a link somewhere to debate it...
Thanks in advance!
I succeeded to show a form looking exactly like one in VBA. I mean to be all the time on top of CorelDRAW application window even with or without focus. Being able to receive text in its own text boxes. I used form.Show() but I succeeded to define it like a child of Corel application window...
What is strange regarding events would be the next described behavior:
- If pageChange event is subscribed from the docker itself class it is unstable. It works (updates some text boxes on the docker) for maximum twenty times. Most of the time less...
- If pageChange event is subscribed from a Windows form updating text boxes on that form it is more stable and works for much more times. It looks it is a maximum times allowed by corel and it never worked more then 582 times. I had enough patience to press the arrow increasing page dimensions and counting the pressing number in another text box...
Now I am a little confused... I do not know if this different corel behavior is connected or not with the class of subscribing or with the interface having the text boxes to be updated.
I am trying to fill the same text boxes of the docker from the form code but I can not...
How should I do docker text boxes updating from a different class?
I was trying :
1 2 3 4
DockerUI dockUI = new DockerUI(corelApp); MessageBox.Show(dockUI.txtTest.Text); dockUI.txtTest.Text = "test"; MessageBox.Show(dockUI.txtTest.Text);
First MessageBox returns the value on the text box in the moment of DockerUI class instantiation and the second one returns 'test', but the text in the docker text box is not updated at all...
I tried to make the docker class static in order to use it without instantiating but I did not have success neither... Can anybody help me on that issue?
Brilliant!
Now I have a docker button lunching the form:
1 2 3 4 5
private void btShowForm_Click(object sender, RoutedEventArgs e) { frmCorel frmC = new frmCorel(corelApp, this); frmC.Show(new WindowWrapper(WinGetHandle("CorelDRAW", hwnd))); }
Not using ShowDialog(), but using Show(). It's a way to make the new form a child of CorelDRAW application Windows form. As CorelDRAW is not an IWin32Window we need a wrapper to transform its handle in such a Window.. The process handler and Wrapper class in the next code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
IntPtr hwnd = IntPtr.Zero; public static IntPtr WinGetHandle(string wName, IntPtr hWnd) { foreach (Process pList in Process.GetProcesses()) { if (pList.MainWindowTitle.Contains(wName)) { hWnd = pList.MainWindowHandle; break; } } return hWnd; } public class WindowWrapper : System.Windows.Forms.IWin32Window { public WindowWrapper(IntPtr handle) { _hwnd = handle; } public IntPtr Handle { get { return _hwnd; } } private IntPtr _hwnd; }
Now, so launched form behaves exactly like a VBA form. It stays all the time on top of CorelDRAW application, even with focus or without and takes keys in its text boxes when it has focus... A kind of VBA form having SowModal property set to False.
You can test this, i dont have heavy files for test,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
using System.Threading; namespace PageTest { public class PageActiveController2 { private Corel.Interop.VGCore.Application corelApp; public delegate void PageActiveEventHandler(Corel.Interop.VGCore.Page Page); private PageActiveEventHandler pageActive; private Corel.Interop.VGCore.Page prevPage; private bool running = false; private Thread Process; private int refreshTime = 0; public event PageActiveEventHandler PageActive { add { StartThread(); pageActive += value; } remove { StopThread(); pageActive -= value; } } public PageActiveController2(Corel.Interop.VGCore.Application corelApp,int refreshTime = 100) { this.corelApp = corelApp; this.refreshTime = refreshTime; } private void StartThread() { running = true; if (Process == null) { Process = new Thread(new ThreadStart(ThreadProcess)); } Process.IsBackground = true; Process.Start(); } private void StopThread() { running = false; if(Process != null) Process.Abort(); Process = null; } private void ThreadProcess() { while (running) { if (corelApp.ActivePage != prevPage) { prevPage = corelApp.ActivePage; if (pageActive != null && prevPage != null) pageActive(prevPage); } Thread.Sleep(refreshTime); } } } }
Usage exemple
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
using System; using System.Windows; using System.Windows.Controls; using corel = Corel.Interop.VGCore; namespace PageTest { public partial class DockerUI : UserControl { private corel.Application corelApp; PageActiveController2 pg2; public DockerUI(corel.Application app) { this.corelApp = app; InitializeComponent(); this.Unloaded += DockerUI_Unloaded; pg2 = new PageActiveController2(app,1500); pg2.PageActive+=pg2_PageActive; } void DockerUI_Unloaded(object sender, RoutedEventArgs e) { pg2.PageActive -= pg2_PageActive; } void updateMyUI(string[] data) { lba_pageName.Dispatcher.Invoke(new Action(() => {lba_pageName.Content = data[0];})); lba_numShapes.Dispatcher.Invoke(new Action(() => { lba_numShapes.Content = data[1]; })); } void pg2_PageActive(corel.Page Page) { updateMyUI(new string[2] { Page.Name, Page.Shapes.Count.ToString() }); } } }
Very interesting!
I gave it a try and I like it very much. I will play more tomorrow... I learned already a lot. So, if I will need to create a thread in order to catch the page change i must find an algorithm to define prevSizeWidth against Page.SizeWidth and so on.
Now, what I could observe that is need to be improved:
When you close CorelDRAW the ThreadProcess is still running and you receive an error at line 5 in the next code :
1 2 3 4 5 6 7 8 9 10 11 12 13
private void ThreadProcess() { while (running) { if (corelApp.ActivePage != prevPage) //error after Corel Application stop { prevPage = corelApp.ActivePage; if (pageActive != null && prevPage != null) pageActive(prevPage); } Thread.Sleep(refreshTime); } }
The unload event of the docker must stop it...
Another thing to be improved, at least understood (by me...) is the time to refresh the labels. I mean it takes more then one second. I tried to modify refreshTime from existing value of 100 to 10 but the necessary time to update has been increased instead of decreasing like I hopped...
"pg2.PageActive -= pg2_PageActive;" already exists in DockerUI_Unloaded method.
I also added "pg2.StopThread(); " but for nothing...
I tried to catch the error but also strange. It is a matter of 'unhandled' error... See the picture:
I tried a break point on the line 97 at the beginning of the stopThread method but it looks that this one is not called before ThreadProcess...
Even more. I put a breakpoint inside DockerUI_Unloaded method but error appears before that.. There I tried to use "pg2.running = false;" after making running variable public.