writing a .net activex control for your sidebar gadget..
HTML is quite easy for people to get started with, pretty broadly known, light weight, rich enough (if you work hard at it or have nice graphics), etc.. so there is a good set of reasons why the sidebar folks chose HTML as the presentation technology [ I am guessign here]
However, there are some things that are a little harder to do with HTML [at least they are for me] ... for example, charting (pie charts) ...I tried using VML for this, and had issues.. (it was a little unstable on how it rendered, some times it would stop rendering, I could not figure why)... so for these very extreme scenarios, I am thinking ActiveX might be OK...
Note that by no means I am advocating activex as the best choice for gadgets, imho the activex registration (regsvr32) breaks the easy, per-user, non-impactful deployment model for gadgets... but I am thinking that there are enterprises (say internal, lob gadgets) that can get away with an impactful deployment model (via MSI or SMS) and benefit from the rich visualization of an activex -say for some BI KPIs...
Here is what I created code to do:
- An Interface so I can 'raise' some events from my activex to my gadget (outward )
- An interface so I can call from my gadget into the Active X... (inwar)
- An ActiveX user control, written in C# that shows UI
- some lame code to draw a piechart... just to make me feel good .... it does not update, etc.. very much a token .. I will skip on steps below
- Wrote the code to call the activex from my gadget and sink to the events..
For reference, here are some good articles in creating .NET Activex controls for IE... I used a little bit from all of these..
https://msdn.microsoft.com/msdnmag/issues/02/01/UserCtrl/
https://www.codeproject.com/cs/miscctrl/exposingdotnetcontrols.asp
https://msdn.microsoft.com/library/default.asp?url=/workshop/author/om/event_model.asp
Come on dude, get to it... show us the code!..
OK .. here you go ... All of the code is commented, please go through it in the project... here I am showing only the 4 tasks above.. |f you are to reuse this, you will have to replace all the lines that have a TODO with your own guids or your own names code
1.
// Outgoing interface, wired via ComSourceInterfaces on my main class -- see step 3
//TODO: Replace the Guid with our own
[Guid("56726927-833B-4cfb-94D3-D1501DFD30D2")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IGadgetControlEvents
{//TODO: The DispIds must be unique and must be here... I first skipped them and was getting a MethodNotImplementedException [DispId(1)]
void RightClickRelay(int x, int y);
[DispId(2)]
void MouseEnterRelay();
[DispId(3)]
void MouseLeaveRelay();
}
In my class, I had to expose the events ( showing only RightClick here... the rest you can see in the code)
// Right Mouse Click will be passed to the gadget... I was hoping I could popup the context menu..
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
if (e.Button == MouseButtons.Right)
{
// Did any one subscribe ???
if (RightClickRelay != null)
{
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
// fire the event ..
RightClickRelay(e.X, e.Y);
CodeAccessPermission.RevertAssert();
}
}
}
2 -- Exposing an interface for gadget to call my Activex ..
// incoming interface -- so I can call from HTML Gadget ....
// wired simply by my control class implementing it..
// note: I had to implement extra interface because I had the eventing interface... if I did not have eventing, I would not have
// needed to explicitly implement this extra interface..
//TODO: Replace guid...
[Guid("341F46AA-0EA0-4b97-A294-E131D8CFF7E6")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IGadgetIncoming
{
void SetVariableName(string name, string value);
}
to wire the interface, simply implement it in my class ... (see step3 )
3.- Creating the activex .. it is simply a .NET Class Library with a UserControl and some attributes:
// TODO: Replace GUID
[Guid("A4B9C3C2-8DAC-451a-AEC1-DE3B042FB311")]
// TODO: Replace Prog Id
[ProgId("WindowsFormsUserControl.UserControl")]
//Wire up my eventing interface ..(ComSource)...
[ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(IGadgetControlEvents))]
[ComVisible(true)]
public partial class UserControl1 : UserControl, IGadgetIncoming
5.- Using the object from my gadget
<!-- using the object tag to call my ActiveX -->
<object id="sample"
classid="clsid:A4B9C3C2-8DAC-451a-AEC1-DE3B042FB311"
height="126" width="126" style="background-color:Transparent;" onclick="alert('clicked');" >
</object>
<script>
<!-- one of several ways to sync event; another way is using the FOR statement -->
function
sample::RightClickRelay ( x, y )
{
// ShowContextMenu ();
var o = document.getElementById('sample');
o.SetVariableName ( 'test1' , 'value1') ; }
</script>
---
So, the control is pretty trivial... download the sample code, replace the TODOs ( use GuidGen to generate your guids) and you will reuse it ... There were however a couple of note worthy issues I have not figured out .. [will get to these as soon as I have time ]
- I implemetned the right click so that I could fire the context menu of the gadget .. but the event is raised and I handled it in Javascript, but still could not fire the context menu ..
- I implemented MouseEnter/Mouse Leave because gadgets show the little drag & drop handle when MouseEnter or it gets focus... One way to get around it, was that I put a Table around it... this way, the table detects when MousEnter/leave happens and lets the sidebar know ... This works for the most part, but if you run you mouse very fast into the gadget, some times table does not fire it ..
- When you put the activex, you lose the easy drag & drop functionality gadget has.. you an only drag & drop from outside the activex..
None of these are blockers, in fact some of the MS gadgets themselves (notes) have these issues but I would like to solve them for a different post ...
You can download the code for this project here...
There are two directories in the download, the sample.gadget and the ActiveX code itself..
For dev/test deployment, the project in Visual Studio is using the "Register for COM Interop" checkbox in the Build section of the Project properties to do the registration ... if you are not rebuilding it, or installing it in a box where you are not building it, you will have to register it manually from a .NET Command prompt (or a command prompt with regasm in the path)..
regasm /register /codebase WindowsFormsuserControl.dll
This leaves the whole topic of how to deploy at run-time... are you going to need admin, etc.. I will have to get back to these questions in a future (but will try to not make it to far into the future) post.. .
Cheers,
Comments
Anonymous
October 09, 2006
In my earlier post , I talked about WPF in the Sidebar by using the IFRAME to host XBAPs. In this post,Anonymous
October 09, 2006
Karsten Januszewski vient de poster, sur son blog, la 2ème partie de son article consacrée à la réalisation...Anonymous
October 12, 2006
to override the default gadget context menu, add an 'oncontextmenu' handler to your HTML element, and inside that handler, (in addition to showing your custom context menu), set 'window.event.returnValue' to 'false' so the default context menu doesn't show up.