ActiveX control in ironpython windows form - winforms

I'm having difficulties with a set of activeX controls used for automation of lab instruments. I've got them all to work in VB, in forms applications - as they won't work in console applications. My company is working mainly with python and there would thus be a great advantage in writting our drivers in python, mainly for lims integration.
As such, I have tried to embed my activeX controls within ironpython windows forms. I've tried two different ways of introducing my controls in the forms:
1) with clr referencing the Ax dll after using AxImp on the original ocx. Then I add my instance of the control as a form control and try to run it from there. It throws System.Windows.Forms.AxHost+InvalidActiveXStateException.
import clr
clr.AddReferenceToFileAndPath(r"C:\dlls\AxVCode3Lib.dll")
clr.AddReferenceByPartialName("System.Windows.Forms")
import System.Windows.Forms as Forms
import AxVCode3Lib
class activeXform(Forms.Form):
def __init__(self):
a = AxVCode3Lib.AxVCode3()
self.Controls.Add(a)
for i in self.Controls:
r = i.Initialize("serial")
print r
form = activeXform()
raw_input(">exit")
2) Using SystemReflection and the ProgID, which throws a generic "Exception has been thrown by the target of an invocation". The following code was introduced in a basic ironpython windows form, however I was not able to add those objects as form controls.
import System.Type
import System.Reflection
import System.Array
oType = System.Type.GetTypeFromProgID("VCODE3.VCode3Ctrl.1")
o = System.Activator.CreateInstance(oType)
args = System.Array[str](['serial'])
try:
r = oType.InvokeMember("Initialize", System.Reflection.BindingFlags.InvokeMethod, None, o, args)
print r
except Exception as e:
print e
Now I suspect both those examples fail due to some properties missing in my forms. However I can't figure out what it is, in particular in case 1 when the instance is actually added as a control, it seems I am very close.

You cannot use the methods of the ActiveX control until its native handle is created. In other words, not until after you call the form's Show() method.
Make sure you get the basic outline of a Winforms application correct, peek in the Program.cs source code file of a sample C# Winforms app. The Application.Run() call is essential. Use the form's Load event (or override OnLoad) as the first event where you can actually start using the control.

Related

Ironpython with pycharm: Drawing and Forms

This is probably a very noob question. I am trying to get some basic code from sharpdevelop into Pycharm. The code basically just draws a window and place some fields and buttons using Windows forms. I've set the interprter in Pycharm to be Ironpython. There seems to be something wrong with the import statements. When I run the following (Which is just a copy paste from code that is perfectly working in sharpdevelop):
import System.Drawing
import System.Windows.Forms
class MainForm(Form):
def __init__(self):
self.InitializeComponent()
def InitializeComponent(self):
self._checkBox1 = System.Windows.Forms.CheckBox()
self._comboBox1 = System.Windows.Forms.ComboBox()
self._label1 = System.Windows.Forms.Label()
#rest of code ...
I get the following message
ImportError: No module named Drawing
You will need to add a reference to the DLLs. It's three lines:
import clr
clr.AddReference("System.Drawing")
clr.AddReference("System.Windows.Forms")
SharpDevelop takes care of adding the references in Program.py (the file that runs). It imports the MainForm class, instantiates it, and displays the form.
Since I am assuming this is the file you run, you will need to add the references within the same file.

How to show Excel ribbon when it is embedded in Webbrowser

Using the suggestion from here, I managed to embed Excel 2007 in my WPF WebBrowser control. However, the ribbon doesn't show up. I tried various techniques and nothing makes it work.
I tried this:
_application.ExecuteExcel4Macro("SHOW.TOOLBAR(\"Ribbon\",True)");
I also tried to run this from a macro after the Excel workbook is constructed,
Sub hide_ribbon()
Application.ExecuteExcel4Macro ("Show.Toolbar(""Ribbon"", False)")
End Sub
Sub show_ribbon()
Application.ExecuteExcel4Macro ("Show.Toolbar(""Ribbon"", True)")
End Sub
but it doesn't work either, although the same macro works fine in native Excel.
Also tried this:
CommandBar cb = _workbook.CommandBars["Standard"];
cb.Visible = true;
cb.Enabled = true;
cb.Position = MsoBarPosition.msoBarTop;
Or tried changing "Standard" to "Ribbon", but nothing works.
Ctrl+F1 doesn't work either.
Anybody got a clue?
It took me over 3 weeks of digging to work this out - even then I still need to test that it all works as expected.
As you already know the ribbon is automatically hidden when embedding Excel and that you need to 'toggle' it back on again by sending an OLE command.
I assume that you are uisng the SHDocVw library wrapped in with an ActiveX container, in the manner described in the knowledge base article is article http://support.microsoft.com/kb/304662 and that you have set up the appropriate registry entries to get the browser to display Excel docs (I am sure that you must have done if all you are missing is the Ribbon).
I am using C#, so you may have to mess about a bit in VBA.
The article entitled "WebOCHostVB.exe Hosts the WebBrowser Control in Visual Basic .NET" in the MS support knowledge base looks promising however, the URL is "support.microsoft.com/kb/311303"
Once the document is opened, call ExecWB on the browser as follows :
object omissing = System.Reflection.Missing.Value ;
this.axExcelWebBrowser1.ExecWB(SHDocVw.OLECMDID.OLECMDID_HIDETOOLBARS,
SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER,
ref omissing, ref omissing);
This should toggle the Ribbon state - as it is off when we start, a single call should make it display. Doing this again should hide it - though I have not tried.
The constants are in the shdocvw.dll that you must reference from your project. Even though these are integer enumerations, I could not redefine them locally and get things to work.
You can find other OLE commands, that might also be useful for your application, here :
http://msdn.microsoft.com/en-us/library/ms691264%28v=VS.85%29.aspx
I don't know why this has to be so difficult, or why the behaviour of Excel is not consistent with that of Word.
Hope this helps.

Sharing Linq to SQL DataContext between WP7.1 and WPF apps?

I have built a WP7.1 application that uses a local database. I used sqlmetal to generate the data context as per this article. http://blogs.microsoft.co.il/blogs/alex_golesh/archive/2011/05/24/windows-phone-mango-what-s-new-local-database-part-1-of-8.aspx
This works as expected using this in the ViewModel.
context = new BirdsnBflysDC("DataSource='isostore:BirdsnBflys.sdf'");`
I am now attempting to "share" the Model and ViewModel code with a WPF application. Initially I added the appropriate files as a link to the WPF project. Creating an instance of the context didn't work so as a test I have added just the data context code to a WPF project and attempt to create an instance of the context in the Loaded event handler as follows.
BirdsnBflysDC context = new BirdsnBflysDC("DataSource='C:\BirdsnBflys.sdf'");
DataContext = context;
The code actually has the complete path to the database. When I step through this in the debugger the context initialization in the data context quits running as if there was an exception, the second line of code above is never reached and the WPF window is shown as if things completed correctly.
I've tried several variation in the DataSource string including "|DataDirectory|\\BirdsnBflys.sdf" all with the same result.
Any suggestions as where to go with this? How to figure out what isn't working correctly?
Thanks,
Dave
The problem is that what is expected in the connection string is different for the two environments.
WP7 works with this.
context = new BirdsnBflysDC("DataSource='isostore:BirdsnBflys.sdf'");
WPF works with this.
context = new BirdsnBflysDC("|DataDirectory|\BirdsnBflys.sdf");
If you give WPF a file name that isn't there you get no error information, the instantiation of the data context fails quietly and any additional code does not get executed.
Dave
Did you remove the 2 methods from the generated cs file? I mean the methods unsupported by mango.
public ExternalDB(System.Data.IDbConnection connection) :
base(connection, mappingSource)
{
OnCreated();
}
public ExternalDB(System.Data.IDbConnection connection,
System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
I am not sure about this, but they might be needed for wpf.
Hope this helps.

Is there a way to use Ruby and WPF?

I found "Ruby in Steel," but that (I think) only works with visual studio 2008 and doesn't support the new WPF/XAML.
Is there such a thing or are these pipe dreams? :)
Look at DiskUse project in your IronRuby 1.1\Samples\ directory. It uses WPF and XAML. For example, it's how they load xaml:
module DialogUtil
def load_xaml(filename)
f = IO::FileStream.new(filename, IO::FileMode.Open, IO::FileAccess.Read)
begin
element = Markup::XamlReader::Load(f)
ensure
f.close
end
element
end
module_function :load_xaml
end
and then using it:
#window = DialogUtil.load_xaml("mainWindow.xaml")
#window.closing { #app.shutdown }
#windowTitle = #window.title
...
#window.show
And yes, it works OK with VS2010 - http://ironruby.codeplex.com/
The main installer for IronRuby does support VS 2010. It also supports Silverlight, but it doesn't seem to support WPF.
Maybe it would be possible to use it by manually editing the project file and writing the boilerplate code that VS usually generates yourself.
EDIT: After some testing, it seems you can use WPF from Iron Ruby without any problems, but you can't use XAML directly.

Change Default Winform Icon Across Entire App

Can I change the default icon used on a Winform?
Most of my forms have their icon property set to a custom icon. For the few forms that slip through the cracks, I don't want the generic "hey look, he made this in visual studio" icon.
One solution is to tediously check every one of my forms to make sure they either have a custom icon set or have ShowIcon set to False.
Another solution is to have every one of my forms inherit from a base class that sets a custom icon in the constructor.
Aside from those solutions, what other options do I have?
EDIT:
I was hoping there would be a way to replace the source of the stock icon with my own. Is it in a resource file somewhere? Or is it embedded in a .NET dll that I can't (or really, really shouldn't) modify?
BOUNTY EDIT:
Is there a way to accomplish this without editing or writing a single line of code? I don't care how impractical, complicated, waste-of-time the solution is... I just want to know if it's possible. I need to satisfy my curiosity.
The default icon is embedded in the winforms dll - looking at reflector (DefaultIcon) it is:
defaultIcon = new Icon(typeof(Form), "wfc.ico");
There is no magic in there that checks another common location, so you can't do it without changing code.
You could always embrace the forces of darkness with field-based reflection? Note: this is hacky and brittle. On your own head! But it works:
[STAThread]
static void Main() {
// pure evil
typeof(Form).GetField("defaultIcon",
BindingFlags.NonPublic | BindingFlags.Static)
.SetValue(null, SystemIcons.Shield);
// all forms now default to a shield
using (Form form = new Form()) {
Application.Run(form);
}
}
To do it properly; two common options;
a base Form class which has the icon set
a factory Form method - perhaps something like:
code:
public static T CreateForm<T>() where T : Form, new() {
T frm = new T();
frm.Icon = ...
// any other common code
return frm;
}
Then instead of:
using(var frm = new MySpecificForm()) {
// common init code
}
Something like:
using(var frm = Utils.CreateForm<MySpecificForm>()) {
}
Of course - that isn't much prettier! Another option might be a C# 3.0 extension method, perhaps as a fluent API:
public static T CommonInit<T>(this T form) where T : Form {
if(form != null) {
form.Icon = ...
//etc
}
return form;
}
and
using(var frm = new MySpecificForm().CommonInit()) {
// ready to use
}
This is then just a .CommonInit() away from your existing code.
The base class option is the one that we use.
If you are looking for an alternative (not necessarily good ones), you could:
1. Use IOC to instantiate all of your forms and modify the IOC container to set the application icon.
2. Use AOP to insert code into all of the forms that sets the application icon.
Personally, I'd just use the base class...
My useful answer:
No
Would be a nice feature for microsoft to implement though, since most apps use the same icon across the entire application.
If you want to update all the icons by another one, you can build a small app that edits all the *.Designer.vb files (in vb.net) and adding the folowing line to InitializeComponent:
Me.Icon = New System.Drawing.Icon("C:\PathTo\icon.ico")
Hope it helps.
If all your forms are in just one project then you can take the dll of the project and use reflection to get every type in the dll. If the type derives from Form you can set the type's Icon property to whatever you want. I am not sure what the performance overhead will be if the project is very big.

Resources