Click here to Skip to main content
15,885,278 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I'm working on a small project, where I need a DataGrid where a column contains an imageButton as a UserControl.

What I'm struggling with is how to bind the image source to the image in my UserControl.

I stripped everything down to only have this function left and I guess I'm just missing something small to get it run.

Any help would be most welcome.


My UserControl:
XML
<UserControl x:Class="OpenPointList.UserControls.DataGridButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <Grid x:Name="LayoutRoot">
        <Button Click="DataGridButton_Click">
            <Button.Template>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border x:Name="Border" 
                            BorderThickness="0"
                            removed="LightBlue">
                        <Border.Child>
                            <StackPanel Orientation="Horizontal">
                                <Image Name="ButtonImage" 
                                       Source="{Binding Image}"/>
                                <TextBlock Name="ButtonText" 
                                           Text="{Binding Text}"/>
                            </StackPanel>
                        </Border.Child>

                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>

                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames
                                            Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty="(Background).(Color)">
                                            <EasingColorKeyFrame KeyTime="0"
                                                                 Value="Red"/>
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>

                                <VisualState x:Name="Pressed"/>
                                <VisualState x:Name="Disabled"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Button.Template>
        </Button>
    </Grid>
</UserControl>


C#
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace OpenPointList.UserControls
{
    /// <summary>
    /// Interaction logic for DataGridButton.xaml
    /// </summary>
    public partial class DataGridButton : UserControl
    {
        public DataGridButton()
        {
            InitializeComponent();
            //this.DataContext = this;
        }

        public ImageSource Image
        {
            get { return (ImageSource)GetValue(ImageProperty); }
            set { SetValue(ImageProperty, value); }
        }
        public static readonly DependencyProperty ImageProperty =
            DependencyProperty.Register("Image", typeof(ImageSourceConverter), typeof(DataGridButton), new UIPropertyMetadata(null));

        public string Text
        {
            get { return (String)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(DataGridButton), new UIPropertyMetadata(""));

        public event RoutedEventHandler Click;
        private void DataGridButton_Click(object sender, RoutedEventArgs e)
        {
            if (Click != null)
            {
                Click(this, e);
            }
        }
    }
}


My Model for the data:
C#
using System;
using System.ComponentModel;
using System.Windows.Media;

namespace OpenPointList.Model
{
    public class OplItem : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        #region Fields

        private int _number;
        private string _statusImage;

        #endregion // Fields

        #region Properties

        public int Number 
        { 
            get { return _number; } 
            set 
            { 
                _number = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Number"));
            } 
        }
        
        public string StatusImage 
        { 
            get { return _statusImage; }
            set
            {
                _statusImage = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("StatusImage"));
            }
        }

        #endregion // Properties
    }
}


My ViewModel:
C#
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;

using OpenPointList.Model;

namespace OpenPointList.ViewModel
{
    public class MainWindowViewModel
    {
       #region Fields

        ObservableCollection<OplItem> _opl;
        private string _image1 = "pack://application:,,,/Image1_32x32.png";
        private string _image2 = "pack://application:,,,/Image2_32x32.png";
        private ICommand _addOplItemCommand;

        #endregion // Fields

        #region Constructor

        public MainWindowViewModel()
        {
            _opl = new ObservableCollection<OplItem>();
            _opl.Add(new OplItem() { Number = 1, StatusImage = _image1 });
            _opl.Add(new OplItem() { Number = 2, StatusImage = _image1 });
            _opl.Add(new OplItem() { Number = 3, StatusImage = _image1 });
            AddOplItemCommand = new RelayCommand(param => this.AddOplItem());
        }

        #endregion // Constructor

        #region Properties

        public ObservableCollection<OplItem> Opl
        {
            get { return _opl; }
            set { _opl = value; }
        }

        #endregion // Properties

        #region AddOplItemCommand

        /// <summary>
        /// Returns the command that, when invoked, will add a new item to the OPL.
        /// </summary>
        public ICommand AddOplItemCommand
        {
            get { return _addOplItemCommand; }
            set { _addOplItemCommand = value; }
        }

        #endregion // AddOplItemCommand

        #region AddOplItem

        /// <summary>
        /// Add a new item to the OPL.
        /// </summary>
        private void AddOplItem()
        {
            _opl.Add(new OplItem() { Number = _opl.Count + 1, StatusImage = _image1 });
            _opl[_opl.Count - 2].StatusImage = _image2;
        }

        #endregion // AddOplItem
    }
}


And my View:
XML
<Window x:Class="OpenPointList.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:userControls="clr-namespace:OpenPointList.UserControls">

    <Grid x:Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <DataGrid Name="OplDataGrid" 
                  AutoGenerateColumns="False" CanUserAddRows="False"
                  ItemsSource="{Binding Opl}">
           
            <DataGrid.Columns>
                <DataGridTextColumn Header="No." Width="30" 
                   Binding="{Binding Path=Number,
                             UpdateSourceTrigger=PropertyChanged}"/>

                <DataGridTemplateColumn Header="UserControl without Binding">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <userControls:DataGridButton
                               Image="pack://application:,,,/Image1_32x32.png"
                               Text="Hello"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

                <DataGridTemplateColumn Header="UserControl with Binding">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <userControls:DataGridButton
                                Image="{Binding Path=StatusImage,
                                       UpdateSourceTrigger=PropertyChanged}" 
                                Text="{Binding Path=Number, 
                                       UpdateSourceTrigger=PropertyChanged}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

                <DataGridTemplateColumn Header="Image">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Image Source="{Binding Path=StatusImage,
                                   UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

        <Button Content="Add Item" Grid.Row="1" Width="50" 
                Command="{Binding Path=AddOplItemCommand}"/>
    </Grid>
</Window>


C#
using System.Windows;

namespace OpenPointList
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}


And for completeness also the remaining files:
XML
<Application x:Class="OpenPointList.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
             <!--StartupUri="MainWindow.xaml">-->
    
    <Application.Resources>
    </Application.Resources>
    
</Application>


C#
using System;
using System.Windows;
using OpenPointList.ViewModel;

namespace OpenPointList
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        static App() { }

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            OpenPointList.MainWindow window = new MainWindow();

            // Create the ViewModel to which the main window binds.
            MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
            window.DataContext = mainWindowViewModel;
            window.Show();
        }
    }
}


The RelayCommand class is from the this MSDN Article: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx:
C#
using System;
using System.Diagnostics;
using System.Windows.Input;

namespace OpenPointList
{
    /// <summary>
    /// A command whose sole purpose is to relay its functionality to other
    /// objects by invoking delegates. The default return value for the CanExecute
    /// method is 'true'.
    /// </summary>
    public class RelayCommand : ICommand
    {
        #region Fields

        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;

        #endregion // Fields

        #region Constructors

        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action<object> execute) : this(execute, null)
        {
        }

        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        #endregion // Constructors

        #region ICommand Members

        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        #endregion // ICommand Members
    }
}
Posted

1 solution

Give the last entry in this blog a try.[^]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900