Wayne K. wrote:
@button1.set_Location(System::Drawing::Point.new(47, 54))
Is there a reason why you’re calling the property setter
method explicitly rather than using the property name? Or is
this not supported in the Ruby.Net method binder?
Our compiler would be happy with it as a property assignment, but we did
it that way inside InitializeComponent in order to ensure round
tripping. When parsing InitializeComponent and generating the codeDOM
representation we need to distinguish between a field, a property and a
method call. Statically typed languages are expected to use type
information to distinguish. As we have no type information we use
syntactic conventions to distinguish between them. Note - these
syntactic conventions only apply within the InitializeComponent method
which is typically auto-generated. Ruby programmers are free to use the
more Rubyish syntax elsewhere in their code.
You don’t need to do this, I think. You can work out from the context
what is a field, a property and a call. I did have some initial trouble
distinguishing between a Property (System.Windows.Form.BackColor.Red)
and an enum (System.Windows.Form.BorderStyle.Sizable) - but it worked
out ok.
Another issue is statically distinguishing between variables such as Foo
and type references such as System::Drawing::Point - we use
wrapper/helper methods to distinguish type references (except when
invoking a new method where we implicitly assume that the constant is a
type reference). Again, this is only necessary inside
IntializeComponent.
I didn’t have that problem. But what I did have a problem with was
something like this (from a TreeNode control):
treeNode3 = System::Windows::Forms::TreeNode.new(‘Node0’, [treeNode1,
treeNode2])
Here, the FormDesigner needs to know the type of the array - which Ruby
of course doesn’t give you. That took a bit of time to get right.
And now a question for your VS integration experts: when adding a new
event handler - how do you arrange for the cursor to be automatically
placed inside the body of the new method?
I’m sure there are several ways to do this, but this is what I did:
-
I have two files - the form code file and the designer file (as in
C#). In the CodeDomProvider, I override the Parse method and before I
parse the designer file to generate the CodeDom, I scan the form file
looking for event handlers. I use regexps to do this - I don’t bother
Ruby parsing the form file at all. I then build a list containing the
names and positions of any event handlers.
-
I then Ruby parse (using Antlr) the designer file and generate the
CodeDom from that. When a delegate is required I do something like this:
CodeMemberMethod cmm = new CodeMemberMethod();
cmm.Parameters.Add(new
CodeParameterDeclarationExpression(typeof(object), “sender”));
cmm.Parameters.Add(new
CodeParameterDeclarationExpression(typeof(System.EventArgs), “e”));
cmm.Name = eventHandlerName;
// let the provider process adding the event handler
int line = _provider.AddEventHandler(eventHandlerName);
cmm.UserData.Add(typeof(Point), new Point(0, line + 1));
The AddEventHandler method does the business of finding any event
handler in the form code, generating it if required (again in the form
code - not the designer code) and returning its position. The last bit
is the code that lets the FormDesigner know where the event handler is
when you double click on the control in the form.
Something similar happems when you drop a new control on the form.
Splitting the form code from the designer makes life a whole lot simpler
and the coding is then clear and unambiguous. And most importantly from
my point of view, it’s easily maintainable.
Dermot