Frage

I have a DataGrid in a user control (DataGridView). This usercontrol propagates a binding to DataGrid's ItemsSource from anywhere in the application and fills it with List of K.

For this example lets define clas for K that has some properties with custom attributes:

public class Foo
{
    [Enumeration(IsEnum=true, EnumerationType=typeof(MessageType))] //MessageType is enumeration and is consisted of values: 'Error', 'Warning' and 'Info'
    public MessageType MessageType { get; set; }

    [Enumeration(IsEnum=true, EnumerationType=typeof(FooType))] //FooType is enumeration and is consisted of values: 'Sweet' and 'Salty'
    public FooType FooType { get; set; }
 }

DataGrid has an event for autogenerating columns.

private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        foreach (Attribute attribute in (e.PropertyDescriptor as System.ComponentModel.PropertyDescriptor).Attributes)
        {
            Utilities.EnumerationAttribute enumAttribute = attribute as Utilities.EnumerationAttribute;

            if (enumAttribute != null
                && enumAttribute.IsEnum)
            {
                DataGridTemplateColumn templateColumn = new DataGridTemplateColumn();

                templateColumn.CellTemplate = (DataTemplate)Resources["enumTemplate"];

                e.Column = templateColumn;
            }
        }
        e.Column.IsReadOnly = true;
   }

Resource for "enumTemplate" is defined in MergedDictionary as DataTemplate

<DataTemplate x:Key="enumTemplate">
    <StackPanel>
        <ComboBox/>
    </StackPanel>
</DataTemplate>

What I was intending to do is to set ItemsSource of each ComboBox the grid will generate with return value of Enum.GetNames(enumAttribute.EnumerationType) which is of type string[].

Now there is a lot of anonymity here and I don't know names of properties, their types or even the type of object this DataGrid would display during the run time.

I had several tries into this ... like defining a property DataSourcesList of type List> where NamedArray holds items to fill the combobox and a name of the property (from e.PropertyName) so that I know which of the NamedArray to use for combobox being generated ... something like:

 DataSourcesList.Add(new DataSourceWithMappedName<System.Object>() { MappedName = e.PropertyName, SourceList = Enum.GetNames(enumAttribute.EnumerationType) });

And then altering DataTemplate:

<DataTemplate x:Key="enumTemplate">
    <DataTemplate.Resources>
        <converters:IListToItemsSource x:Key="ilistToItemsSource"/>
    </DataTemplate.Resources>
    <StackPanel>
        <ComboBox ItemsSource="{Binding DataSourcesList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:DataGridView}}, Converter={StaticResource ilistToItemsSource}, ConverterParameter={Binding somethingButAllInVaine}}"/>
    </StackPanel>
</DataTemplate>

, but this can't be done since ConverterParameter is not a DependencyObject and can not be bound.

Maybe I should state that the same principle should be later used for binding collections and not just enums.

So please, can anyone help me with a solution to generic ComboBox representation in a generic GridView.

Tnx and happy coding.

War es hilfreich?

Lösung

Perhaps it would be easier to set the DataTemplate up in code. Start by defining the datatemplate and then setting the ComboBox ItemSource Binding Source to the List of String resulting from the Enum.GetNames().

Code Way

        // Create template
        DataTemplate newTemplate = new DataTemplate();
        FrameworkElementFactory stackFactory = new FrameworkElementFactory(typeof(StackPanel));
        FrameworkElementFactory comboFactory = new FrameworkElementFactory(typeof(ComboBox));
        Binding newBinding = new Binding();
        newBinding.Source = Enum.GetNames(typeof(enumAttribute.EnumerationType));
        comboFactory.SetBinding(ComboBox.ItemsSourceProperty, newBinding);
        stackFactory.AppendChild(comboFactory);
        newTemplate.VisualTree = stackFactory;

        // Set the template
        templateColumn.CellTemplate = newTemplate;

XAML / Code Way*

<CollectionViewSource x:Key="EnumCollection"/>

<DataTemplate x:Key="enumTemplate"> 
    <StackPanel>
        <ComboBox ItemsSource="{Binding Source={StaticResource EnumCollection}}" />
    </StackPanel>
</DataTemplate>

Code (Make sure you set the Collection Source):

CollectionViewSource enumCollection = (CollectionViewSource)this.FindResource("EnumCollection");
enumCollection.Source =Enum.GetNames(typeof(enumAttribute.EnumerationType));

Pure Xaml

<ObjectDataProvider x:Key="EnumCollection"
                    MethodName="GetValues"
                    ObjectType="{x:Type sys:Enum}">
    <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="YourEnum" />
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

<DataTemplate x:Key="enumTemplate"> 
    <StackPanel>
        <ComboBox ItemsSource="{Binding Source={StaticResource EnumCollection}}" />
    </StackPanel>
</DataTemplate>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top