I have just started WPF and am a bit lost.
<DataGrid Name="dgResults" AutoGenerateColumns="True" ItemsSource="{Binding}">
</DataGrid>
private void GetServices(string strComputer)
{
ManagementScope scope = new ManagementScope(@"\\" + strComputer + @"\root\cimv2");
SelectQuery query = new SelectQuery("Select * From Win32_Service");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection services = searcher.Get();
dgResults.ItemsSource = services;
}
I was expecting that the WMI Win32_Service query would show the WMI properties as the headers and each object in the returned collection would be displayed as a row. But it is showing the ManagementObjectCollection properties. Is there a way to convert it and still allow all properties to be accessible?
Any help would be much appreciated.
This is a little tricky thing.
First, since you don't want to display CLR properties of ManagementBaseObject
instances, you have to use type descriptors concept to tell the binding engine, that you have custom bunch of properties. Here's descendants of CustomTypeDescriptor
and PropertyDescriptor
you'll need:
internal sealed class ManagementObjectPropertDescriptor : PropertyDescriptor
{
private readonly PropertyData propertyData;
public ManagementObjectPropertDescriptor(PropertyData propertyData)
: base(propertyData.Name, null)
{
this.propertyData = propertyData;
}
public override bool CanResetValue(object component)
{
return false;
}
public override Type ComponentType
{
get { return typeof(ManagementObjectTypeDescriptor); }
}
public override object GetValue(object component)
{
return propertyData.Value;
}
public override bool IsReadOnly
{
get { return true; }
}
public override Type PropertyType
{
get { return propertyData.Value != null ? propertyData.Value.GetType() : typeof(object); }
}
public override void ResetValue(object component)
{
}
public override void SetValue(object component, object value)
{
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
public sealed class ManagementObjectTypeDescriptor : CustomTypeDescriptor
{
private PropertyData[] managementObjectProperties;
public ManagementObjectTypeDescriptor(ManagementBaseObject source)
{
this.managementObjectProperties = source
.Properties
.Cast<PropertyData>()
.ToArray();
}
public override PropertyDescriptorCollection GetProperties()
{
return new PropertyDescriptorCollection(managementObjectProperties
.Select(p => new ManagementObjectPropertDescriptor(p))
.ToArray());
}
}
For simplicity properties are made read-only.
Next, you need to turn ManagementObjectCollection
into collection of ManagementObjectTypeDescriptor
:
ManagementScope scope = new ManagementScope(@"\\" + strComputer + @"\root\cimv2");
SelectQuery query = new SelectQuery("Select * From Win32_Service");
var typeDescriptors = new ObservableCollection<ManagementObjectTypeDescriptor>();
using (var searcher = new ManagementObjectSearcher(scope, query))
{
using (var managementObjects = searcher.Get())
{
foreach (ManagementBaseObject managementObject in managementObjects)
{
using (managementObject)
{
typeDescriptors.Add(new ManagementObjectTypeDescriptor(managementObject));
}
}
}
}
dgResults.ItemsSource = new ArrayList(typeDescriptors);
Note, that ItemsSource
is a non-generic implementation of IList
. The DataGrid
has a buggy, from my point, behavior here: if you'll set a generic IList<ManagementObjectTypeDescriptor>
as the items source, DG
will just ignore the fact of inheritance from CustomTypeDescriptor
, and you'll see no columns in the grid at all. At the same time, non-generic IList
works as expected.