Using image in bool-type column when using AutoGenerateColumn (WPF)

1.6k views Asked by At

I have

if (e.PropertyType == typeof(bool))
        {             
           e.Column.Header = "Status";
           DataGridTemplateColumn templateColumn = new DataGridTemplateColumn();
           templateColumn.Header = "Status";
           DataTemplate imageTemplate = new DataTemplate();

           DataTrigger imageBoolTrigger = new DataTrigger();
           Converter.BoolToImage boolToImage = new Converter.BoolToImage();

           Uri trueImageURI = new Uri(@"pack://application:,,,/MonitorView_wpf;component/Images/Icons/check-mark-16.png", UriKind.RelativeOrAbsolute);

           boolToImage.TrueImage.Source = new BitmapImage(trueImageURI);

           imageBoolTrigger.Binding = new Binding { Converter = boolToImage, ConverterParameter = e.Column };

           imageTemplate.Triggers.Add(imageBoolTrigger);
           templateColumn.CellTemplate = imageTemplate;

           e.Column = templateColumn;

        }

but alas, its not working.

how do I use an image instead of the autogenerated checkbox?

my converter looks like this:

 public class BoolToImage : IValueConverter
    {
        public Image TrueImage { get; set; }
        public Image FalseImage { get; set; }

        public object Convert(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            if (!(value is bool))
            {
                return null;
            }

            bool b = (bool) value;
            if (b)
            {
                return this.TrueImage;
            }
            else
            {
                return this.FalseImage;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

my image does exist in the assemby, it's a png - ive tried all sorts of things, but never working.

thanks in advance

3

There are 3 answers

0
Mark Feldman On BEST ANSWER

Too much behind-code for my liking, personally I would create a template for it in resources:

    <DataGridTemplateColumn x:Key="booleanImageTemplate">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <Image Name="theImage" Width="64" Height="64" Source="true_image.png"/>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding theBooleanPropertyName}" Value="False">
                        <Setter TargetName="theImage" Property="Source" Value="false_image.png"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>

Then override it on creation:

<Grid>
    <DataGrid AutoGenerateColumns="True" ItemsSource="{Binding}" AutoGeneratingColumn="OnAutogeneratingColumn" />
</Grid>

private void OnAutogeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.Column.Header.ToString() == "theBooleanPropertyName")
            e.Column = (DataGridTemplateColumn)Resources["booleanImageTemplate"];
    }

I've just used an image here (effectively making the column read only) but it would work equally well with a templated checkbox.

4
AjS On

Did you try placing a breakpoint in your converter and see if that code is actually running? Perhaps, a better way to create DataTemplate in code is by using FrameworkElementFactory, so below code should work:-

 if (e.PropertyType == typeof(bool))
  { 
     DataTemplate imageTemplate= new DataTemplate();

     //set up the stack panel
     FrameworkElementFactory imageFactory = new FrameworkElementFactory(typeof(Image));

     Converter.BoolToImage boolToImage = new Converter.BoolToImage();
     Uri trueImageURI = new Uri   (@"pack://application:,,,/MonitorView_wpf;component/Images/Icons/check-mark-16.png",  UriKind.RelativeOrAbsolute);
     boolToImage.TrueImage.Source = new BitmapImage(trueImageURI);
     var binding= new Binding { Converter = boolToImage, ConverterParameter = e.Column };
      imageFactory.SetBinding(Image.SOurceProperty,binding);

      //set the visual tree of the data template
      imageTemplate.VisualTree = imageFactory ;

      var templateColumn = new DataGridTemplateColumn();
      templateColumn.Header = "Status";
      templateColumn.CellTemplate=imageTemplate;
      e.Column=templateColumn;
     }

You can also use 'XamlReader' to create template in code.

Below code uses XamlReader to create DataTemplate in code and assign it to CellTemplate.

 var templateColumn = new DataGridTemplateColumn();
 templateColumn.Header = "Status";

 templateColumn.CellTemplate = XamlReader.Parse(GetDataTemplate()) as DataTemplate;
 e.Column = templateColumn;

 public string GetDataTemplate()
    {

        var dt = @"<DataTemplate x:Key=""dt"" xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
    xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
    <Canvas>
       <Ellipse
  Canvas.Top=""5""
  Canvas.Left=""5""
  Fill=""#FFFFFF00""
  Height=""10""
  Width=""10""
  StrokeThickness=""5""
  Stroke=""#FF0000FF""/>
    </Canvas>
    </DataTemplate>";
        return dt;
    }

Note that this uses a Canvas with an ellipse but you can easily put a path.

3
eemwingg On

If my understanding is right, I suggest you set AutoGenerateColumns to false.

And use a converter that converts the boolean value into your desired image. Here is a similar example from my project. Instead of using an image though, I just changed the background color based on the bound boolean value.

<DataGridTemplateColumn Header="5_5" MaxWidth="10">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Textblock Background="{Binding _booleanValue, Converter={StaticResource  ResourceKey=hourSlotColorConverter}, 
                                        UpdateSourceTrigger=PropertyChanged}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

And this is how my converter looks like:

class HourSlotToBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // if value isn't null, we can safely do the conversion. 
            if (value != null)
            {
                if ((bool)value)
                    return Brushes.LimeGreen;
            }

            return Brushes.White;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

I hope this helps.