Search code examples
c#wpfdata-bindingdatatemplatecode-behind

How to set Datatemplate binding based on object type from code?


Don't ask why, but I have to create a WPF Listview in the business logic part of the code (the reason is I'm dealing with legacy code, thats why.)

Anyway, so far everything works, however, I want to add a checkbox column called "PermutationItem", where only some of the items have the corresponding property. In case a property doesn't have the property (= has the wrong type), I want to set the IsEnabled flag of the Checkbox to false automatically. This is the code so far:

ListView lvPlatformList = new ListView()
{
    Name = "MyListView"
};
lvPlatformList.BorderThickness = new Thickness(1);
lvPlatformList.Margin = new Thickness(0, HeightMargin, 25, HeightMargin);
var gridView = new GridView();

DataTemplate dtEnabled = new DataTemplate() { DataType = typeof(CheckBox) };
FrameworkElementFactory cbfEnabled = new FrameworkElementFactory(typeof(CheckBox));
cbfEnabled.SetBinding(CheckBox.IsCheckedProperty, new Binding("IsEnabled"));
dtEnabled.VisualTree = cbfEnabled;
gridView.Columns.Add(new GridViewColumn()
{
    Header = "Enabled",
    CellTemplate = dtEnabled
});

gridView.Columns.Add(new GridViewColumn()
{
    Header = "Equipment Name",
    DisplayMemberBinding = new Binding("Equipment.Name")
    {
        FallbackValue = "Empty Platform"
    },
});

DataTemplate dtPermutationItem = new DataTemplate() { DataType = typeof(CheckBox) };
FrameworkElementFactory cbfPermutationItem = new FrameworkElementFactory(typeof(CheckBox));
cbfPermutationItem.SetBinding(CheckBox.IsCheckedProperty, new Binding("Equipment.IsPermutationItem.Value")
{
    FallbackValue = false
});
cbfPermutationItem.SetBinding(CheckBox.IsEnabledProperty, /* What comes here?? */);
dtPermutationItem.VisualTree = cbfPermutationItem;
gridView.Columns.Add(new GridViewColumn()
{
    Header = "PermutationItem",
    CellTemplate = dtPermutationItem
});
lvPlatformList.View = gridView;

I know how I would solve this in XAML, but how can it be done here in the code?


Solution

  • I was able to solve it using a separate Binding with a new IValueConverter class. Instead of IsEnabled I used the Visibility property, but the same procedure is applicable to any property.

    Here is the new Bindig:

    cbfPermutationItem.SetBinding(CheckBox.VisibilityProperty, new Binding("Equipment")
    {
        Converter = new DataTypeToVisibilityConverter(),
        ConverterParameter = typeof(MyTargetClass)
    });
    

    And here is the corresponding Visibility Converter:

    public class DataTypeToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return Visibility.Hidden;
    
            Type compareType = parameter as Type;
            Type valueType = value.GetType();
    
            if (compareType.IsAssignableFrom(valueType))
            {
                return Visibility.Visible;
            }
            else
            {
                return Visibility.Hidden;
            }
    
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    You can obviously put whatever you want into the converter, however a thing to note here is that IsAssignableFrom() function was needed in my case to work with inherited types.