WPF ComboBox for Interface types - c#

I am currently building an application that contains a structure similar to this:
public class ViewModel
{
public string property1 {get;set;}
public string property2 {get;set;}
public ISomeInterface interfaceProperty {get;set;}
}
Which then has several different classes defined that implement ISomeInterface.
Is there a way to represent the interfaceProperty as a combobox of choices that would let me change the type that is stored there, without resorting to wiring that all up in the code behind?
Extra wrinkle, I would also like to show some databound textboxes to configure various properties in the selected type, which would change when the type is changed, is this possible?

Is there a way to represent the interfaceProperty as a combobox of choices that would let me change the type that is stored there, without resorting to wiring that all up in the code behind?
Maybe, depending on what you actually want to do. If you simply want to bind a collection of existing objects to the ComboBox as the selection options, that should work fine. But obviously in that case, if you are using this UI with more than one instance of your ViewModel type, each instance would wind up with the same ISomeInterface object for a given implementation type. This may or may not be acceptable.
If you want to automatically detect all available implementations of ISomeInterface and populate the ComboBox with the types themselves, creating a new instance for the ViewModel each time the selected implementation changes, then no…that's going to require some code-behind.
If you do want unique object instances, but are okay with manually specifying the options, then you could do it with e.g. a collection of factory delegates, or implementation of IValueConverter (e.g. to convert a string or Type value from the ComboBox to a new instance of the desired type).
Unfortunately, your question is light on requirements, so it's hard to know what would work for you. There are lots of options, and enumerating them all would be "too broad" for Stack Overflow.
I would also like to show some databound textboxes to configure various properties in the selected type, which would change when the type is changed, is this possible?
Sure. Just declare appropriate DataTemplate resources for the different types you want to handle, and use ContentPresenter with the Content bound to the instance of the type you want to display.

Related

Is it possible to view members other than public properties in a PropertyGrid?

Is it possible to view members other than public properties in a PropertyGrid? The documentation says "all public properties of the SelectedObject will be displayed in the PropertyGrid by default". The "by default" seems to imply that it may be possible to view e.g. fields or non-public properties after some configuration.
Please note that I do not actually want to display anything other than public properties, I just need to know what it supports.
So basically you want control over what is displayed inside a property grid. Yes that is possible.
An object may provide custom information about itself by implementing an interface ICustomTypeDescriptor. If this is not implemented, the static TypeDescriptor is used by the property grid.
So we need to implement ICustomTypeDescriptor.
The property information will be returned by the interface method GetProperties(). This method returns an object of type PropertyDescriptorCollection.
Edit: You should take a look at PropertyGrid.BrowsableAttributes for a simpler solution. Programatically Hide Field in PropertyGrid
Some useful links -
.NET Matters: ICustomTypeDescriptor, Part 1
http://www.codeproject.com/Articles/4448/Customized-display-of-collection-data-in-a-Propert

Can PropertyGrid be used without an object?

I have an application in which I need to edit some data, and PropertyGrid structure is visually the best candidate for my needs. However, PropertyGrid takes the public properties of an object and displays them in the grid. (additional options with attributes). However, I don't have such an object, because the list of key-value pairs I need to edit is dynamic.
The ideal solution would be something like this:
public class GridParam
{
// ... several constructors here, one for each type
// ... or a single one but with generic class, does not matter
public String Name { get; set; }
public Object Value { get; set; }
public Type ItemType { get; set; }
}
GridParam stringParam = new GridParam("Address", "2534 Barkeley Av.");
GridParam numberParam = new GridParam("Year", 2012);
NewKindOfPropertyGrid grid = new NewKindOfPropertyGrid();
grid.AddParam(stringParam);
grid.AddParam(numberParam);
The above code would generate a property grid that looks like this:
Is something like this possible with PropertyGrid or any other existing control (which at least looks similar to PG)? The syntax does not have to be similar to what I've written, but it would need to be able to accept a collection of such properties that can be dynamic, without having to define a class...
You have two options here.
The first (and simpler, IMO) is to implement the ICustomTypeDescriptor interface on a class that takes an IEnumerable<T> of your GridParam instances.
The PropertyGrid class doesn't actually use reflection directly; instead, it uses a TypeDescriptor class to get metadata about an instance of an object, which by default uses reflection.
However, if you implement ICustomTypeDescriptor, then the PropertyGrid will get all the information it would get from a TypeDescriptor from your implementation. You just have to feed it what you want it to show.
So in this case, you'd have the GetProperties implementation return a PropertyDescriptorCollection populated with a PropertyDescriptor for each of your GridParam instances.
The other, much more difficult (possibly) option is to dynamically create the type, and have it bind to that (since PropertyGrid takes an object to bind to). Of course, you're really replicating on some level most of what an implementation of ICustomTypeDescriptor would do, so it's probably better to go with the former.

What would be the easiest way to provide a way to configure a tree of objects to the user?

So I have an object tree that looks similar to this:
AbstractA
string PropA
int PropB
AbstractC PropC
AbstractD PropD
AbstractB
string PropA
string PropB
AbstractC : AbstractB
string PropC
AbstractD : AbstractB
int PropC
ConcreteA1 : AbstractA
int PropE
ConcreteC1 : AbstractC
bool PropD
ConcreteC2 : AbscractC
decimal PropD
ConcreteD1 : AbstractD
string PropD
ConcreteD2 : AbstractD
long PropD
The issue I'm having is finding a comprehensive way to provide the user with the ability to configure the object tree. There are multiple concrete classes that extend my abstracts and I would like to refrain from building a user control for every concrete type. To throw an additional constraint in the mix, the class definition is coming from my WCF proxy class. I'd like to avoid rolling my own proxy/model definitions if at all possible, but if the only way to accomplish my goal is to do so then so be it.
I originally tried to use PropertyGrid but my knowledge of it is pretty weak and I wasn't having much luck googling any good examples last night.
it sounds like you are using .net on both sides of the interaction and have control of both sides. if this is the case, instead of generating proxy classes, you could put the contracts into a common assembly referenced by both the service and the client and use the contract classes and interfaces directly instead of using generated proxies and thereby have complete control over the classes being used and have the ability to use whatever attributes you desire.
To avoid building a control for each type, you need to use reflection on each object's properties and convert the data to and from easy to manipulate strings. A grid control with two columns, the left side for property names and the right for their values (as strings). When an edit takes place, converts the value to the right type. Every base type has an inherit converter that is relatively easy to access.
Your grid/listview needs to be a list of properties, and these properties need to map to your class instance. The list of objects will represent each property of the item(your concrete object). The list of objects will need to remember a few things, the item, the property info of the property and the value, plus whatever else you want the grid to do based on the property information.
Using Reflection and TypeConverter's you can get at each property and edit their values and therefore create one control(the grid/listview of properties for a class instance) to edit any of your classes.

Change "ToString" for a sealed class

I have a class I am working with:
public sealed class WorkItemType
It's ToString is weak (Just shows Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType).
Is there any way to override this to show the name of the WorkItemType?
Normally I would just aggregate the value in a new class, but I am using this for bindings in WPF (I want to have a list of WorkItemTypes in a combo box and assign the selected value to a bound WorkItemType variable.)
I think I am out of luck here, but I thought I would ask.
A fairly neat way to do it might be to add an extenesion method to the WorkItemType object. Something like this:
public static class ToStringExtension
{
public static string MyToString(this WorkItemType w)
{
return "Some Stuff"
}
}
Then you could call something like
WorkItemType w = new WorkItemType;
Debug.WriteLine(w.MyToString();)
Do you need to override ToString? If you are in control of the code where the object is displayed, you can always provide a FormatWorkItemType method, or something to that effect.
WPF provides a few different built-in ways to do this right in the UI. Two I'd recommend:
You can use ComboBox's
DisplayMemberPath to display a single
property value but still select from
the WorkItemType objects.
If you want to display a composite of
a few properties you can change the
ComboBox's ItemTemplate to make it
look pretty much however you want -
formatting text, adding borders,
colors, etc. You can even set up the
DataTemplate to automatically be
applied to any WorkItemType object
that gets bound anywhere in your UI
(same basic effect from UI
perspective as changing ToString) by
putting it into Resources and giving
it only a DataType with no x:Key.
You're out of luck :-(
You could write your own class that wraps the WorkItemType and delegate down to it (a proxy) expect for the ToString:
class MyWorkItemType
{
private WorItemType _outer;
public MyWorkItemType(WorkItemType outer)
{
_outer=outer;
}
public void DoAction()
{
_outer.DoAction();
}
// etc
public override string ToString()
{
return "my value"
}
}
I don't have any C# knowledge, but can't you wrap your extended class inside another class? Proxy all method calls to the extended class, except toString(), Also very hackish, but I thought I'ld bring it up anyway.
Doing some sorta magic with reflection is probably your only hope. I know you can instantiate private constructors with it, so maybe you can override a sealed class... Note, this should be your last resort if there is seriously no other way. Using reflection is a very hackish/improper way of doing it.
In addition to the other WPF-specific answer you could use an IValueConverter in the binding to format / display the WorkItemType however you want. This has an advantage of being reusable (if you want to display the object in some other control, for instance.)
There are many examples of using converters here. This other question should be pretty similar to the ComboBox usage mentioned here. The answers note that you can either make the converter work on the entire collection of objects, or work on one item at a time. The latter might be the more reusable approach.

Make properties available for data binding through some kind of interface in .NET?

I have a class that implements properties in a specific way, to handle some custom requirements for our business logic system.
This "specific way" makes the properties non-operational in the context of data binding. Basically, if I drop an object of our class onto a form, data binding finds nothing on the object, and the property inspector for that object, though it lists the properties, doesn't allow me to edit them.
What I'm wondering is if there's an interface or similar that I can implement in my class that will report to the form designer what properties could be bound to, and that implements the custom code necessary to talk to the data binding system on behalf of my properties.
Note that I do not need to be able to edit the property values for my object in the property inspector, that was just an example of how non-functional the properties are. I just need the data binding support.
Is there such an interface, and if so, what is it?
Let's give a simple example.
Let's assume I have this class:
public class CustomDataBinding : Component
{
private Dictionary<String, Object> _Properties = new Dictionary<String, Object>();
public CustomDataBinding()
{
_Properties["Property1"] = 10;
_Properties["Property2"] = "Test";
}
}
Is there anything I could do to my object, short of actually making the properties, that would add data binding support for those two "properties"?
Note that for my real class, I know the type of every property, so if it makes it easier, change the above code to just use string values:
public class CustomDataBinding : Component
{
private Dictionary<String, String> _Properties = new Dictionary<String, String>();
public CustomDataBinding()
{
_Properties["Property1"] = "Property1";
_Properties["Property2"] = "Property2";
}
}
I will also need validation support, as our class can report validation status for every property as well, but I have already implemented IDataErrorInfo and IDataValidationInfo which I think will give me that. I have also implemented INotifyPropertyChanged, so I got the change mechanism in place I think, but I need to discover and talk to the properties. Beyond those interfaces, anything else I should look into would be welcome information.
It sounds like you are describing a property-bag; this is indeed supported for data-binding, but you need to implement ICustomTypeDescriptor or TypeDescriptionProvider. The available properties are then defined via TypeDescriptor.GetProperties(obj) or TypeDescriptor.GetProperties(type) - or in the case of lists, via ITypedList. ICustomTypeDescriptor is suitable if the properties change per-instance; TypeDescriptionProvider can do per-type customisation, and works with things like BindingList<T> without any extra work.
The tricky thing is that you need to define the type of each property - not simple if you've just got object. Here is a very simplified example, that treats all properties as strings. In this example, because we are binding a list, it uses ITypedList but doesn't implement ICustomTypeDescriptor.
Note that for PropertyGrid, a simpler shortcut is to use a TypeConverter - this allows you to tweak the properties without having to use ICustomTypeDescriptor or TypeDescriptionProvider - see example.
You could always expose the Dictionary as a property and access elements of it directly (though it'd need to be by index and implement IListSource or IEnumerable.
-- Edit
I must say, though, you're effectively making your own untyped language. Interested in the reason for this, perhaps there is a better way ...
Since you can't publish new properties, how about publishing your Dictionary as an ObservableDictionary<string, object>. See this DrWPF article.
You could then bind to the dictionary using the key to get the named property you're after.

Categories

Resources