Here are some usefull Options to tick in the C# 2010 Options Dialog Box
To Show the Configuration and Platform options in the Project property Debug Window
Projects and Solutions - General - Show Advance build configurations
To redirect output to the immediate window
Debbugging - General - Redirect all output window text to the Immediage window
How to change the Exception Handling Options
Tools - Customize - Commands
Menu bar: Debug
Click where you want to put the new Command, in the controls dialog box
Add Command, Debug, Exceptions...
Ok, Close
Tuesday, July 24, 2012
Friday, July 20, 2012
Excel Tip of the Day: INDIRECT
The INDIRECT function is a pretty hard function to understand at first glance.
However all you need to know is this
1) It converts a string into a cell Reference
2) It does not work with named formula
3) INDIRECT is a volatile function
4) It is often used in conjuction with the function ADDRESS
1) It converts a string into a cell Reference
=INDIRECT("A1")
Is equivalent to a foruma =A1
=INDIRECT("TblOrders")
it gives you back a reference to the TblOrders Table. This is Equivalent to a formula =TblOrders
The advantage is that you can form the string using formulas to make dyamically build reference to table objects
2) INDIRECT does not work with named formula
if you have a named formula like myrange =OFFSET($A$1,1,0,COUNTA($A:$A)-1,1)
and then you use =INDIRECT("myrange") this will not be equivalent to =myrange.
However if you do something like myrange = $A$3:$C$10
and then you type =INDIRECT("myrange") this will work fine and will be equal to =myrange
This means that if you are trying to use in a list validation INDIRECT(C3) where C3="mylist" and
mylist = OFFSET($A$1,1,0,COUNTA($A:$A)-1,1),
this dynamic validation procedure will fail - INDIRECT is poiting to a named formula
You will instead need to use something like
C3 = "mylistheader", whe mylistheader is a named cell,
mylistheader = $A$1.
mylistheadeCol = $A:$A
OFFSET(INDIRECT(C3),0,0,COUNTA(INDIRECT(A1&"Col")),1)
INDIRECT(C3) = a referece to $A$1
COUNTA = will count the name in the list
This will work just fine
3) INDIRECT is a volatile function
This mean that Excel recomputes it each time it recalculate the spread sheet. It make the spreadsheet very heavy. Use it sparingly.
4) It is often used in conjuction with the function ADDRESS
to dynamically build range reference
1) It converts a string into a cell Reference
2) It does not work with named formula
3) INDIRECT is a volatile function
4) It is often used in conjuction with the function ADDRESS
1) It converts a string into a cell Reference
=INDIRECT("A1")
Is equivalent to a foruma =A1
=INDIRECT("TblOrders")
it gives you back a reference to the TblOrders Table. This is Equivalent to a formula =TblOrders
The advantage is that you can form the string using formulas to make dyamically build reference to table objects
2) INDIRECT does not work with named formula
if you have a named formula like myrange =OFFSET($A$1,1,0,COUNTA($A:$A)-1,1)
and then you use =INDIRECT("myrange") this will not be equivalent to =myrange.
However if you do something like myrange = $A$3:$C$10
and then you type =INDIRECT("myrange") this will work fine and will be equal to =myrange
This means that if you are trying to use in a list validation INDIRECT(C3) where C3="mylist" and
mylist = OFFSET($A$1,1,0,COUNTA($A:$A)-1,1),
this dynamic validation procedure will fail - INDIRECT is poiting to a named formula
You will instead need to use something like
C3 = "mylistheader", whe mylistheader is a named cell,
mylistheader = $A$1.
mylistheadeCol = $A:$A
OFFSET(INDIRECT(C3),0,0,COUNTA(INDIRECT(A1&"Col")),1)
INDIRECT(C3) = a referece to $A$1
COUNTA = will count the name in the list
This will work just fine
3) INDIRECT is a volatile function
This mean that Excel recomputes it each time it recalculate the spread sheet. It make the spreadsheet very heavy. Use it sparingly.
4) It is often used in conjuction with the function ADDRESS
to dynamically build range reference
Monday, July 16, 2012
Exposing COM Collection With Events
This is a piece of code that shows you how to expose COM Collection with Events in C#.
here you can find the code for the Person Class.
There is only one problem with this code. If you declase the class with Event you need to handle it, i.e you need to define in VBA the event sub. You can just put some empty code inside it. You can see onother interesting post here at murat
UPDATE: I have added a try cach statment to the code to sort the problem mentioned above.
When you declare an Object WithEvents in VBA, the Event in C# will not be null, so the != will not work.
This is why I have protected the code with a try, catch, statement.
And here the VBA code to test it.
here you can find the code for the Person Class.
There is only one problem with this code. If you declase the class with Event you need to handle it, i.e you need to define in VBA the event sub. You can just put some empty code inside it. You can see onother interesting post here at murat
UPDATE: I have added a try cach statment to the code to sort the problem mentioned above.
When you declare an Object WithEvents in VBA, the Event in C# will not be null, so the != will not work.
This is why I have protected the code with a try, catch, statement.
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace MyCOMEvents01 { // To expose properties and methods to COM, you must declare them on the class // interface and mark them with a DispId attribute, and implement them in the class. // The order in which the members are declared in the interface is the // order used for the COM vtable. // ex: // [DispId(1)] // void Init(string userid , string password); // [DispId(2)] // bool ExecuteSelectCommand(string selCommand); //Class Interface [Guid("09a22bef-9826-4ea6-8e12-83adbbc0efd1"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IPerson { [DispId(1)] string Id { get; set; } [DispId(2)] string Name { get; set; } [DispId(3)] double Age { get; set; } } // To expose events from your class, you must declare them on the events // interface and mark them with a DispId attribute. // The class should not implement this interface. //Events Interface [Guid("94d63c5e-125e-4f7d-aa0a-0d62dd4dc4fd"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IPersonEvents { [DispId(101)] void OnAfterNameChange(object sender, string name); [DispId(102)] void OnBeforeNameChange(object sender, string newName, ref bool cancel); } //The Class can also implement other interfaces. But only //the first one will be exposed to COM. //COM Class do not support inheritance beyond interface implementation //Class Employees : List<Employee> is not COM compatible //Class Implement the Class Interface [Guid("0836089b-7099-4c0d-be97-39a009d1a9ba"), ComVisible(true), ClassInterface(ClassInterfaceType.None), ComDefaultInterface(typeof(IPerson)), ComSourceInterfaces(typeof(IPersonEvents)), ProgId("MyCOMEvents01.Person")] public class Person : IPerson { [ComVisible(false)] //Does not need to be visible to COM public delegate void OnAfterNameChangeHandler(object sender, string name); [ComVisible(false)] //Does not need to be visible to COM public delegate void OnBeforeNameChangeHandler(object sender, string newName, ref bool cancel); public event OnAfterNameChangeHandler OnAfterNameChange; public event OnBeforeNameChangeHandler OnBeforeNameChange; public string Id { get; set; } private string _Name; public string Name { get { return _Name; } set { bool cancel = false; if (OnBeforeNameChange != null) { //if we define a COM object WithEvents in VBA, OnPesonAdd will not be null even if we do not associate any code to it. //So we must protect the code. try { OnBeforeNameChange(this, value.ToString(), ref cancel);} catch (Exception){} //Do Nothing } if (cancel == false) { _Name = value; if (OnAfterNameChange != null) { //if we define a COM object WithEvents in VBA, OnPesonAdd will not be null even if we do not associate any code to it. //So we must protect the code. try { OnAfterNameChange(this, _Name); } catch (Exception){} //Do Nothing } } } } public double Age { get; set; } } }
And here the VBA code to test it.
Option Explicit Dim WithEvents ps As MyCOMEvents01.Persons Sub Test() Dim p1 As MyCOMEvents01.Person Dim p2 As MyCOMEvents01.Person Dim key As Variant Set p1 = New MyCOMEvents01.Person Set p2 = New MyCOMEvents01.Person Set ps = New MyCOMEvents01.Persons p1.ID = 1 p1.Name = "Mario" p2.ID = 2 p2.Name = "Pluto" Call ps.Add(p1.ID, p1) Call ps.Add(p2.ID, p2) For Each key In ps Debug.Print ps(key).Name Next End Sub Private Sub ps_OnPersonAdd(ByVal sender As Variant) Debug.Print "Added" End Sub
Exposing COM Events
Hi,
This is a quick sample code that shows you how to expose events to COM.
Just remember to "register the assembly for COM interop" and please do not tick "Make Assembly COM Visible". We use the ComVisible attribute to decise what to make visible for COM interop.
You can find here a quick VBA code to test the classs
This is a quick sample code that shows you how to expose events to COM.
Just remember to "register the assembly for COM interop" and please do not tick "Make Assembly COM Visible". We use the ComVisible attribute to decise what to make visible for COM interop.
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace MyCOMEvents01 { // To expose properties and methods to COM, you must declare them on the class // interface and mark them with a DispId attribute, and implement them in the class. // The order in which the members are declared in the interface is the // order used for the COM vtable. // ex: // [DispId(1)] // void Init(string userid , string password); // [DispId(2)] // bool ExecuteSelectCommand(string selCommand); //Class Interface [Guid("09a22bef-9826-4ea6-8e12-83adbbc0efd1"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IPerson { [DispId(1)] string Id { get; set; } [DispId(2)] string Name { get; set; } [DispId(3)] double Age { get; set; } } // To expose events from your class, you must declare them on the events // interface and mark them with a DispId attribute. // The class should not implement this interface. //Events Interface [Guid("94d63c5e-125e-4f7d-aa0a-0d62dd4dc4fd"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IPersonEvents { [DispId(101)] void OnAfterNameChange(object sender, string name); [DispId(102)] void OnBeforeNameChange(object sender, string newName, ref bool cancel); } //The Class can also implement other interfaces. But only //the first one will be exposed to COM. //COM Class do not support inheritance beyond interface implementation //Class Employees : List<Employee> is not COM compatible //Class Implement the Class Interface [Guid("0836089b-7099-4c0d-be97-39a009d1a9ba"), ComVisible(true), ClassInterface(ClassInterfaceType.None), ComDefaultInterface(typeof(IPerson)), ComSourceInterfaces(typeof(IPersonEvents)), ProgId("MyCOMEvents01.Person")] public class Person : IPerson { [ComVisible(false)] //Does not need to be visible to COM public delegate void OnAfterNameChangeHandler(object sender, string name); [ComVisible(false)] //Does not need to be visible to COM public delegate void OnBeforeNameChangeHandler(object sender, string newName, ref bool cancel); public event OnAfterNameChangeHandler OnAfterNameChange; public event OnBeforeNameChangeHandler OnBeforeNameChange; public string Id { get; set; } private string _Name; public string Name { get { return _Name; } set { bool cancel = false; if (OnBeforeNameChange != null) { //if we define a COM object WithEvents in VBA, OnPesonAdd will not be null even if we do not associate any code to it. //So we must protect the code. try { OnBeforeNameChange(this, value.ToString(), ref cancel);} catch (Exception){} //Do Nothing } if (cancel == false) { _Name = value; if (OnAfterNameChange != null) { //if we define a COM object WithEvents in VBA, OnPesonAdd will not be null even if we do not associate any code to it. //So we must protect the code. try { OnAfterNameChange(this, _Name); } catch (Exception){} //Do Nothing } } } } public double Age { get; set; } } }
You can find here a quick VBA code to test the classs
Option Explicit Dim WithEvents p As MyCOMEvents01.Person Sub test() Set p = New MyCOMEvents01.Person p.Name = "Mario" p.Name = "Ciccio" End Sub Private Sub p_OnAfterNameChange(ByVal sender As Variant, ByVal Name As String) Debug.Print Name End Sub Private Sub p_OnBeforeNameChange(ByVal sender As Variant, ByVal newName As String, cancel As Boolean) If newName = "Ciccio" Then cancel = True Debug.Print "Do not Change Name" End If End Sub
Subscribe to:
Posts (Atom)