dot net objects - IDispatch - and the Visual Studio Property Browser
I have some questions about the new MPF framework classes in Visual Studio 2005.
I have implemented the ISelectionContainer interface in my EditorPane.cs.
When the editor detects the user has selected a shape in our drawing -> All I do is in GetObjects() is set apUnkObjects to my dot net objects.
Somehow, the property browser is smart enough to automatically display my object correctly in the property browser. (I imagine it is auto-magically generating an IDispatch interface behind my back).
Is there a way to tell the property browser what the categories are for my properties?
Is there a way to change the name displayed in the ObjectList? (currently it shows my fully qualified type name. I’d rather it display the instance name of the object selected).
Is there a way to make a comment appear in the Field Descriptions pane at the bottom of the property window?
I’m hoping there are some secret attributes I can use to tag the properties/methods of my dot net object.
I tried to derive my dot net object from ICategorizeProperties, but then I realized this interface refers to the dispIds, which I have no access to.
Best regards,
Daren.
public int GetObjects(uint dwFlags, uint cObjects, object[] apUnkObjects)
{
ShellConstants flags = (ShellConstants)dwFlags;
switch (flags)
{
case ShellConstants.GETOBJS_ALL:
// fall through, same in both cases
case ShellConstants.GETOBJS_SELECTED:
{
for (int i = 0; i < this.selectedObjects.Count; i++)
{
apUnkObjects
= this.selectedObjects
;
} // next selected object
}
break;
default:
return VSConstants.E_INVALIDARG;
} // end switch
return VSConstants.S_OK;
}
#region ICategorizeProperties Members
public int GetCategoryName(int PROPCAT, uint lcid, out string pbstrName) // UNSURE HOW TO USE THIS.
{
throw new Exception("The method or operation is not implemented.");
}
public int MapPropertyToCategory(int dispid, out int ppropcat) // I DON’T KNOW THE DISPIDs!
{
throw new Exception("The method or operation is not implemented.");
}
#endregion
} // end class
} // end namespace
Thanks Gaston,
I removed my implementation of ISelectionContainer from my EditorPane.cs (and saved many lines of ugly C++ like COM code!).
One other challenge I'm having is getting an events tab to appear for my object.
I added the attribute:
[PropertyTabAttribute(typeof(WorkflowObjectPropertyTab), PropertyTabScope.Document)]
to my property adapter class.
And created a new class from the MSDN sample (see below).
But when I click on an object (I can see properties), but I dont see a custom property tab, and none of the methods in the PropertyTab class are ever called (I put breakpoints on them).
Any idea whats going wrong? I imagine my PropertyTabAttribute is not being interpreted correctly in VSIP or at all?
Best regards,
D.
using System;
using System.Drawing;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace Captaris.Workflow.Designer.Drawing.Workflow
{
class WorkflowObjectPropertyTab : System.Windows.Forms.Design.EventsTab
{
[BrowsableAttribute(true)]
// This string contains a Base-64 encoded and serialized example property tab image.
private string img = "AAEAAAD/////AQAAAAAAAAAMAgAAAFRTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj0xLjAuMzMwMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5CaXRtYXABAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAtgIAAAJCTbYCAAAAAAAANgAAACgAAAANAAAAEAAAAAEAGAAAAAAAAAAAAMQOAADEDgAAAAAAAAAAAADO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tn/ztbZztbZHh4eHh4eztbZztbZztbZztbZztbZztbZztbZztbZztbZ/87W2c7W2QDBAB4eHh4eHs7W2c7W2c7W2c7W2c7W2c7W2c7W2c7W2f/O1tnO1tnO1tkAwQAeHh4eHh7O1tnO1tnO1tnO1tnO1tnO1tnO1tn/ztbZztbZlJSU////AMEAHh4eHh4eztbZztbZztbZztbZztbZztbZ/87W2c7W2c7W2ZSUlP///wDBAB4eHh4eHs7W2c7W2c7W2c7W2c7W2f/O1tnO1tnO1tnO1tmUlJT///8AwQAeHh4eHh7O1tnO1tnO1tnO1tn/ztbZHh4eHh4eHh4eHh4eHh4e////AIAAHh4eHh4eztbZztbZztbZ/87W2ZSUlP///wDBAADBAADBAADBAADBAACAAB4eHh4eHs7W2c7W2f/O1tnO1tmUlJT///8AwQAAgAAeHh4eHh7O1tnO1tnO1tnO1tnO1tn/ztbZztbZztbZlJSU////AMEAAIAAHh4eHh4eztbZztbZztbZztbZ/87W2c7W2c7W2c7W2ZSUlP///wDBAACAAB4eHh4eHs7W2c7W2c7W2f/O1tnO1tnO1tnO1tnO1tmUlJT///8AwQAAgAAeHh4eHh7O1tnO1tn/ztbZztbZztbZztbZztbZztbZlJSU////AMEAAIAAHh4eHh4eztbZ/87W2c7W2c7W2c7W2c7W2c7W2c7W2ZSUlP///wDBAACAAB4eHs7W2f/O1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tnO1tn/Cw==";
private IServiceProvider sp;
public WorkflowObjectPropertyTab(IServiceProvider sp) : base(sp)
{
this.sp = sp;
}
// Returns the properties of the specified component extended with
// a CategoryAttribute reflecting the name of the type of the property.
public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, System.Attribute[] attributes)
{
PropertyDescriptorCollection props;
if (attributes == null)
props = TypeDescriptor.GetProperties(component);
else
props = TypeDescriptor.GetProperties(component, attributes);
PropertyDescriptor[] propArray = new PropertyDescriptor[props.Count];
for (int i = 0; i < props.Count; i++)
{
// Create a new PropertyDescriptor from the old one, with
// a CategoryAttribute matching the name of the type.
propArray
= TypeDescriptor.CreateProperty(props
.ComponentType, props
, new CategoryAttribute(props
.PropertyType.Name));
}
return new PropertyDescriptorCollection(propArray);
}
public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component)
{
return this.GetProperties(component, null);
}
// Provides the name for the event property tab.
public override string TabName
{
get
{
return "Events by Type";
}
}
// Provides an image for the event property tab.
public override System.Drawing.Bitmap Bitmap
{
get
{
Bitmap bmp = new Bitmap(DeserializeFromBase64Text(img));
return bmp;
}
}
// This method can be used to retrieve an Image from a block of
// Base64-encoded text.
private Image DeserializeFromBase64Text(string text)
{
Image img = null;
byte[] memBytes = Convert.FromBase64String(text);
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream(memBytes);
img = (Image)formatter.Deserialize(stream);
stream.Close();
return img;
}
} // end class
} // end namespace
Hello,
Well that sounds rather more complicated than I was hoping. Currently, my browse object looks like:
[DefaultProperty("Name")]
[PropertyTabAttribute(typeof(WorkflowObjectPropertyTab), PropertyTabScope.Document)]
public class WorkflowDocumentPropertyAdapter : PropertyAdapter
{
private WorkflowDocument document;
#region properties
[Description("Name of the model."), Category("Default")]
public string Name
{
get
{
return this.document.Name;
}
set
{
ModelChangedEventArgs e = new ModelChangedEventArgs(new ModelChange(ModelChangeType.ObjectValue, this.document.Id, WorkflowObjectType.Document, WorkflowObjectProperty.Name));
this.RaiseBeforeModelChanged(e);
if (e.Cancel)
{
return;
}
this.document.Name = value;
this.RaiseModelChanged(e);
}
}
[Description("Image to display on the design canvas."), Category("Appearance")]
public string BackgroundImage
{
get
{
return string.Empty;
}
}
#endregion properties
} // end class
Are you suggesting that I make WorkflowDocumentPropertyAdapter class implement the IVSMDPerPropertyBrowsing interface?
BTW, I cannot find any reference to this interface in the docs (or for IVSPerPropertyBrowsing). Are you sure that is the correct interface name?
****************
Can anyone from microsoft confirm the proper way to implement property tabs for the property browser in VSIP using the managed classes?
Best regards,
Daren.