65.9K
CodeProject 正在变化。 阅读更多。
Home

如何在 DataGrid 的行中添加动态图像/按钮?

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (8投票s)

2010 年 4 月 9 日

BSD

11分钟阅读

viewsIcon

105424

downloadIcon

2990

通常,您会想要显示一个 DataGrid,但您不想仅仅按原样显示它,您希望能够增强它并为其添加功能,例如在每行的开头添加图像或在每行添加一个按钮。

Title:       How to add a dynamic image and/or a dynamic button to a DataGrid row using a DataGridTemplateColumn and a DataTemplateSelector?
Author:      Jared Barneck 
Email:       rhyous at yahoo
Blog:        http://rhyous.com
Member ID:   6636137
Language:    C#, WPF
Platform:    Windows
Technology:  WPF, WPFToolKit, Visual Studio 2008
Level:       Beginner
Description: Enter a brief description of your article
Section      Platforms, Frameworks & Libraries 
SubSection   Windows Presentation Foundation » Controls
License:     The BSD License 

介绍 

本文最初发布于我的博客 这里。我想与 CodeProject 分享,以回馈我从这个网站上学到的很多东西。

通常,您会想要显示一个 DataGrid,但您不想仅仅按原样显示它,您希望能够增强它并为其添加功能,例如在每行的开头添加图像或在每行添加一个按钮。

因此,在 WPFToolkit 的 DataGrid 中,您可以添加列并为每行添加数据或控件,例如图像或按钮。更好的是,您可以读取行并动态决定在每行中添加什么数据或控件。

在我的用例中,我们正在做类似 PC Doctor 的事情,我们检查一堆值,与默认值进行比较,然后显示一个网格,显示状态是“正常”、“警告”还是“错误”。我们希望为每种状态显示不同的图像。另外,如果状态是警告或错误,我们想要一个“修复”按钮。

首先,我们有一个 Visual Studio 2008 中的 WPF 项目。我们已经安装了 WPFToolKit 并将其引用添加到我们的项目中。

我们使用 DataTable 创建一个表,其外观如下

IntVal StrVal
0 normal
1 warning
2 error

在代码中,您可以将 DataTable 分配给 DataGridDataContext,它将为您完成显示 DataGrid 的工作。

当我们将此传递给 DataGrid 时,我们想添加两列

  1. 我们想添加一个图像,如果它是正常、警告或错误,则该图像不同。
  2. 我们只想在它是警告或错误时添加一个按钮。

因此,视觉效果如下

Image IntVal StrVal 操作
0 normal  
1 warning <button>修复</button>
2 error <button>修复</button>

步骤 1. 安装先决条件:安装 Visual Studio 2008,然后下载并安装 WPFToolkit。

您可能已经完成了这些,这里没有提供相关的步骤。

步骤 2. 在 Visual Studio 2008 中创建一个新的 WPF 项目并设计 WPF 界面

因此,一旦我们的项目创建完成并添加了 WPFToolKit 的引用,我们就更改了默认 Window1 类上的 XAML。

  1. 我们需要在此处的窗口标签中添加对工具包的引用,作为 xmlns(参见第 4 行)。
  2. 我们需要为我们的按钮添加资源。这在 Windows.Resources 部分(介于第 6 行和第 21 行之间)完成。每个资源都是一个 DataTemplate
  3. 我们需要为我们的图像添加三个单独的资源。同样,每个资源都是一个 DataTemplate
  4. 我们需要设置每个 ImageSource 值。目前,我们将使用静态路径指向图像文件。我们还指定,无论图像大小如何,我们都希望它显示为 16x16。有关使用图像的更多信息,请参见本文底部。
  5. 我们需要从 WPFToolkit 引用中添加一个 DataGrid(参见第 23 行)。
  6. 我们需要将 DataGridItemSource 配置为使用 Binding,否则,当 DataTable 分配给 DataContext 时,它将不会显示 DataTable(参见第 23 行)。
Window1.xaml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
<Window x:Class="DataGridAddButtonAndImageColumns.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpftk="http://schemas.microsoft.com/wpf/2008/toolkit"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <DataTemplate x:Key="FixThisTemplate">
            <Button Name="mButtonFixThis" Click="ButtonFixThis_Click">Fix This</Button>
        </DataTemplate>
        <DataTemplate x:Key="NormalTemplate">
        </DataTemplate>
        <DataTemplate x:Key="StatusTemplateNormal" x:Name="mNormalImage">
            <Image Width="16" Height="16" Source="C:\DataGridAddButtonAndImageColumns\DataGridAddButtonAndImageColumns\bin\Debug\Normal.png" />
        </DataTemplate>
        <DataTemplate x:Key="StatusTemplateWarning" x:Name="mWarningImage">
            <Image Width="16" Height="16" Source="C:\DataGridAddButtonAndImageColumns\DataGridAddButtonAndImageColumns\bin\Debug\Warning.png" />
        </DataTemplate>
        <DataTemplate x:Key="StatusTemplateError" x:Name="mErrorImage">
            <Image Width="16" Height="16" Source="C:\DataGridAddButtonAndImageColumns\DataGridAddButtonAndImageColumns\bin\Debug\Error.png" />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <wpftk:DataGrid Name="mDataGrid" ItemsSource="{Binding}" CanUserAddRows="False" IsReadOnly="True"></wpftk:DataGrid>
    </Grid>
</Window>

步骤 3 - 创建数据 

数据可以来自任何地方,但对于这个基本示例,我们只是在构造函数中静态创建了一个 DataTable。这不是关于创建 DataTable 的文档,所以我们不会描述它是如何完成的,但这是代码。

我将说明我们为 DataTableDataTable.DefaultView 添加了一个属性,以便可以轻松访问它们。

Data.cs
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
using System.Data;

namespace DataGridAddButtonAndImageColumns
{
    public class Data
    {
        #region Member Variables
        private DataTable mTable;
        #endregion

        #region Constructors

        /*
         * The default constructor
         */
        public Data()
        {
            mTable = new DataTable();
            mTable.Columns.Add("IntVal", typeof(int));
            mTable.Columns.Add("StrVal", typeof(string));
            DataRow row0 = mTable.NewRow();
            row0["IntVal"] = 0;
            row0["StrVal"] = "normal";
            mTable.Rows.Add(row0);

            DataRow row1 = mTable.NewRow();
            row1["IntVal"] = 1;
            row1["StrVal"] = "warning";
            mTable.Rows.Add(row1);

            DataRow row2 = mTable.NewRow();
            row2["IntVal"] = 2;
            row2["StrVal"] = "error";
            mTable.Rows.Add(row2);

        }

        #endregion

        #region Properties
        public DataTable Table
        {
            get { return mTable; }
            set { mTable = value; }
        }

        public DataView View
        {
            get { return mTable.DefaultView; }
        }
        #endregion

        #region Functions
        #endregion

        #region Enums
        #endregion
    }
}

步骤 4 - 创建实现 INotifyPropertyChanged 的 ViewModel。

因此,创建 ViewModel 并不完全需要,但 Model-View-ViewModel 设计模式确实有好处,所以即使这是一个简单的示例应用程序,我们也试图遵循它。

  1. 我们创建了一个名为 DataViewModel 的新类。
  2. 我们实现 INotifyPropertyChanged 接口:首先,通过将其作为接口添加到我们的对象继承(第 7 行),其次,通过添加该接口所需的功能(从第 44 行开始)(尽管对于这个小型应用程序来说它没有被使用,但我不想省略它,因为您可能需要在您的应用程序中使用它)。
  3. 我们更改了构造函数,以便以前一步中设计的 Data 对象作为参数传入(第 18 行)。
  4. 我们将 Table 和 Table 的视图公开为属性。
DataViewModel.cs
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
using System;
using System.ComponentModel;
using System.Data;

namespace DataGridAddButtonAndImageColumns
{
    public class DataViewModel : INotifyPropertyChanged
    {
        #region Member Variables
        readonly Data mData;
        #endregion

        #region Constructors
        /*
         * The default constructor
         */
        public DataViewModel(Data inData)
        {
            mData = inData;
        }
        #endregion

        #region Properties
        public DataView View
        {
            get { return mData.View; }
        }

        public DataTable Table
        {
            get { return mData.Table; }
        }
        #endregion

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}

步骤 5 - 添加将 DataTable 传递给 DataGrid 的代码

因此,在 Window1.xaml.cs 文件中,我们创建了一个新的 DataViewModel 对象,并将一个新 Data 对象传递给它(第 12 行)。

然后,我们使用 DataViewModel 中的属性将 DataTable 传递给 DataGridDataContext 属性(第 20 行)。

现在代码后台看起来如下

Window1.xaml.cs
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
using System.Windows;
using System.Windows.Controls;

namespace DataGridAddButtonAndImageColumns
{
    public partial class Window1 : Window
    {
        #region Contructor
        public Window1()
        {
            InitializeComponent();
            DataViewModel model = new DataViewModel(new Data());

            // It is ok to pass either the DataTable or the DataView
            // so both lines below work, however I am only using one:
            //
            // mDataGrid.DataContext = model.View;
            // mDataGrid.DataContext = model.Table;

            mDataGrid.DataContext = model.Table;
        }
        #endregion

        #region Functions
        private void ButtonFixThis_Click(object sender, RoutedEventArgs e)
        {
            // Do something here
        }
        #endregion
    }
}

现在我们可以编译并运行,看到我们的简单应用程序,它应该会显示一个 DataGrid,其中包含来自 DataTable 的数据。它看起来会像这样

IntVal StrVal
0 normal
1 warning
2 error

步骤 6 - 创建 DataTemplateSelectors

DataTemplateSelectorDataGridTemplateColumn 使用。当 DataGridTemplateColumn 添加到 DataGrid 时,它将是传递给每个 DataRow 的对象。

由于我们将添加一列图像和第二列按钮,因此我们创建两个继承 DataTemplateSelector 的类。

在创建它们之前,我们希望它们共享一个基类,所以首先,我们将创建一个基类供它们共享。我们不仅仅是为了遵循“最佳实践”而创建基类,而是因为它们都将共享一个返回父 Window1 对象的函数。或者,我们可以为每个 DataTemplateSelector 复制相同的函数,但如果我们更新了函数却忘记了它存在于两个地方怎么办?所以最好让代码只存在于一个地方。

好的,让我们逐步创建这个对象。

  1. 我们创建一个新类并命名为 BaseDataTemplateSelector
  2. 我们在第 7 行继承 DataTemplateSelector
  3. 我们从第 19 行开始添加返回父 Window1 对象的函数。该函数基本上会遍历父对象,直到找到一个 Window1 对象,找到后就返回它。
BaseDataTemplateSelector.cs
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace DataGridAddButtonAndImageColumns
{
    public class BaseDataTemplateSelector : DataTemplateSelector
    {
        #region Constructors
        /*
		 * The default constructor
 		 */
        public BaseDataTemplateSelector()
        {
        }
        #endregion

        #region Functions
        protected Window1 GetWindow1(DependencyObject inContainer)
        {
            DependencyObject c = inContainer;
            while (true)
            {
                DependencyObject p = VisualTreeHelper.GetParent(c);

                if (c is Window1)
                {
                    //mSectionControl = c;
                    return c as Window1;
                }
                else
                {
                    c = p;
                }
            }
        }
        #endregion
    }
}

有了基类后,我们创建一个 ActionDataTemplateSelector 类,用于选择是否为每行添加“修复”按钮。

我们还添加了一个 StatusImageDataTemplateSelector 来选择每行要显示的正确图像。

我们让 ActionDataTemplateSelector 重写 SelectTemplate 函数(第 18 行)。SelectTemplate 是当我们将 DataGridTemplateColumn 添加到 DataGrid 时传递给每个 DataRowView 的。因此,为了控制我们对新列中单元格所做的更改,我们需要重载此函数。

这是我们创建 ActionDataTemplateSelector 的方法。

  1. 我们创建一个新类并命名为 ActionDataTemplateSelector
  2. 让该类继承我们之前创建的 BaseDataTemplateSelector(第 7 行)。它不需要继承 DataTemplateSelector,因为基类已经继承了它。
  3. 我们从第 18 行开始重写 SelectTemplate 函数。
  4. 我们在第 21 行将作为第一个参数传入的 object 强制转换为 DataRowView。您现在应该对它很熟悉了,因为它与 DataTemplateSelector 的工作方式非常相似。当创建 DataGridTemplateColumn 时,对于每个 DataRowView,都会调用 SelectTemplate。传递到 SelectTemplate 函数的对象将是 DataRowView
  5. 我们使用 GetWindow1 函数来查找父 Window1 对象,因为我们需要它的引用,因为它保存着我们的 DataTemplates
  6. 我们从 DataRowView 中获取 IntVal 列中包含的值,并使用它来确定是否添加按钮(请参见第 28 行的 if 语句)。
  7. 如果列是警告或错误列,我们返回修复按钮的 DataTemplate,该行中的单元格将包含并显示该按钮。
ActionDataTemplateSelector.cs
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
using System.Data;
using System.Windows;

namespace DataGridAddButtonAndImageColumns
{
    public class ActionDataTemplateSelector : BaseDataTemplateSelector
    {
        #region Constructors
        /*
		 * The default constructor
 		 */
        public ActionDataTemplateSelector()
        {
        }
        #endregion

        #region Functions
        public override DataTemplate 
        SelectTemplate(object inItem, DependencyObject inContainer)
        {
            DataRowView row = inItem as DataRowView;

            if (row != null)
            {
                Window1 w = GetWindow1(inContainer);
                if (row.DataView.Table.Columns.Contains("IntVal"))
                {
                    if ((int)row["IntVal"] > 0)
                    {
                        return (DataTemplate)w.FindResource("FixThisTemplate");
                    }
                }
                return (DataTemplate)w.FindResource("NormalTemplate");
            }
            return null;
        }
        #endregion
    }
}

StatusImageDataTemplateSelector 也重载了 SelectTempate 函数,并以与上述类似的方式选择状态的正确图像,因此我们不再逐一解释。

我们进行了更多计算,因为每种状态(正常、警告、错误)都有不同的图像,所以我有三个 if 语句从第 28 行开始。

StatusImageDataTemplateSelector .cs
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
using System.Data;
using System.Windows;

namespace DataGridAddButtonAndImageColumns
{
    public class StatusImageDataTemplateSelector : BaseDataTemplateSelector
    {
        #region Constructors
        /*
		 * The default constructor
 		 */
        public StatusImageDataTemplateSelector()
        {
        }
        #endregion

        #region Functions
        public override DataTemplate SelectTemplate(object inItem, DependencyObject inContainer)
        {
            DataRowView row = inItem as DataRowView;

            if (row != null)
            {
                if (row.DataView.Table.Columns.Contains("IntVal"))
                {
                    Window1 w = GetWindow1(inContainer);
                    int status = (int)row["IntVal"];
                    if (status == 0)
                    {
                        return (DataTemplate)w.FindResource("StatusTemplateNormal");
                    }
                    if (status == 1)
                    {
                        return (DataTemplate)w.FindResource("StatusTemplateWarning");
                    }
                    if (status == 2)
                    {
                        return (DataTemplate)w.FindResource("StatusTemplateError");
                    }
                }
            }
            return null;
        }
        #endregion
    }
}

步骤 7 - 创建添加新列的函数,并让构造函数调用每个函数。

现在我们有了在添加列时修改每行的工具,我们可以添加代码来创建两个新列。这在 Window1.xaml.cs 中完成。

每个函数将包含四行

  1. 创建一个新的 DataGridTemplateColumn
  2. 为其 Header 分配一个字符串。此字符串将显示为列标题。
  3. 创建我们创建的每个 DataTemplateSelector 对象(ActionDataTemplateSelectorStatusImageDataTemplateSelector)的新实例,并将其分配给 DataGridTemplateColumnCellTemplateSelector
  4. 将新的 DataGridTemplateColumn 添加/插入到 DataGrid 中。

下面是应该添加到 Window1.xaml.cs 中的两个函数,用于执行所述步骤

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
public void CreateActionButtonColumn()
{
    DataGridTemplateColumn actionColumn = new DataGridTemplateColumn { CanUserReorder = false, Width = 85, CanUserSort = true };
    actionColumn.Header = "Action";
    actionColumn.CellTemplateSelector = new ActionDataTemplateSelector();
    mDataGrid.Columns.Add(actionColumn);
}

public void CreateStatusColumnWithImages()
{
    DataGridTemplateColumn statusImageColumn = new DataGridTemplateColumn { CanUserReorder = false, Width = 85, CanUserSort = false };;
    statusImageColumn.Header = "Image";
    statusImageColumn.CellTemplateSelector = new StatusImageDataTemplateSelector();
    mDataGrid.Columns.Insert(0, statusImageColumn);
}

别忘了在构造函数中调用这些函数。请参见第 13 行和第 14 行的两个调用。

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
public Window1()
{
    InitializeComponent();
    DataViewModel model = new DataViewModel(new Data());

    // It is ok to pass either the DataTable or the DataView
    // so both lines below work, however I am only using one:
    //
    // mDataGrid.DataContext = model.View;
    // mDataGrid.DataContext = model.Table;

    mDataGrid.DataContext = model.Table;
    CreateActionButtonColumn();
    CreateStatusColumnWithImages();
}

好的,您现在完成了。如果编译并运行程序,它应该就可以工作了。

在调试模式下运行它,您将看到它在运行时遍历每个创建的对象。

现在您应该已获得期望的输出,并且应该理解如何向 DataGrid 添加包含动态数据或控件的列。

Image IntVal StrVal 操作
0 normal  
1 warning <button>修复</button>
2 error <button>修复</button>

不使用静态路径处理图像的选项

上面的示例是静态调用图像的,但在实际实现中,这会产生问题,因为每个程序都安装在不同的位置,并且用户通常可以选择安装位置。

您有两种选择来解决这个问题,我们将向您展示如何做到这一点

  1. 嵌入您的图像
  2. 使用位于相对路径中的图像文件

这两种方法都有效。第二种方法使得品牌推广更容易,因为不需要重新编译代码来更改图像,因为图像文件可以简单地替换。

嵌入您的图像

因此,您可以将图像嵌入为资源并使用嵌入式资源。要嵌入它们,请执行以下操作

  1. 在 Visual Studio 中,在您的项目下创建一个名为“Images”的文件夹。
  2. 将您的图像复制到该文件夹中。
  3. 在 XAML 中,像这样更改每个图像资源行
	<Image Width="16" Height="16" Source="Images\Warning.png" />
使用位于相对路径中的图像文件

我决定不嵌入我的图像,而是通过使用相对路径来解决这个问题。我倾向于让图像来自可执行文件启动目录的相对路径的图像目录中的实际文件。

\MyFolder\
\MyFolder\program.exe
\MyFolder\Images\
\MyFolder\Images\Normal.png
\MyFolder\Images\Warning.png
\MyFolder\Images\Error.png 

因此,为了使用相对路径,我们创建了另一个继承 IValueConverter 的对象。

我们这样做的方式如下

  1. 创建一个名为 PathConverter 的新类。
  2. 让它继承 IValueConverter(第 7 行)。
  3. 实现 IValueConverter 接口所需的方法(第 19 行和第 45 行)。
  4. Convert 函数中添加代码。我们只使用 Convert 方法,不需要使用 ConvertBack 方法,所以我们将保持未实现状态。
  5. value 参数强制转换为 DataRowView。您现在应该熟悉它了,因为它与 DataTemplateSelector 的工作方式非常相似。每个 DataRowView 都将作为第一个 object 参数传入。
  6. 使用 System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) 获取相对路径(可执行文件启动的路径)。
  7. DataRowView 获取状态值,并添加几个 if 语句,返回相对路径 + 图像文件路径。
PathConverter.cs
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
using System.Data;
using System.Globalization;
using System.Windows.Data;

namespace DataGridAddButtonAndImageColumns
{
    public class PathConverter : IValueConverter
    {
        #region Constructors
        /*
		 * The default constructor
 		 */
        public PathConverter()
        {
        }
        #endregion

        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            DataRowView row = value as DataRowView;
            if (row != null)
            {
                if (row.DataView.Table.Columns.Contains("IntVal"))
                {
                    String workingDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                    int status = (int)row["IntVal"];
                    if (status == 0)
                    {
                        return workingDirectory + @"\Normal.png";
                    }
                    if (status == 1)
                    {
                        return workingDirectory + @"\Warning.png";
                    }
                    if (status == 2)
                    {
                        return workingDirectory + @"\Error.png";
                    }
                }
            }
            return null;
        }

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

好的,我们还没有完成。现在我们需要再次编辑 XAML。我们没有 PathConverter 对象的实例。我们可以在 XAML 的 Windows.Resources 部分创建一个实例。

创建后,我们可以将每个 DataTemplate 中的 Image 对象更改为绑定到转换器,并将转换器分配给我们之前在 XAML 中实例化的 PathConverter 对象。

以下是步骤。

  1. 我们添加了一个 xmlns 引用来加载本地命名空间(第 5 行)。
  2. 我们在 Windows.Resources 中添加了 PathConverter 的实例。
  3. 我们将 Image Source 值更改为:
    Source="{Binding Converter={StaticResource ImagePathConverter}}"
     
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
<Window x:Class="DataGridAddButtonAndImageColumns.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpftk="http://schemas.microsoft.com/wpf/2008/toolkit"
    xmlns:local="clr-namespace:DataGridAddButtonAndImageColumns"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:PathConverter x:Key="ImagePathConverter" />
        <DataTemplate x:Key="FixThisTemplate">
            <Button Name="mButtonFixThis" Click="ButtonFixThis_Click">Fix This</Button>
        </DataTemplate>
        <DataTemplate x:Key="NormalTemplate">
        </DataTemplate>
        <DataTemplate x:Key="StatusTemplateNormal" x:Name="mNormalImage">
            <Image Width="16" Height="16" Margin="3,0" Source="{Binding Converter={StaticResource ImagePathConverter}}" />
            <!--<Image Width="16" Height="16" Source="Images\Normal.png" />--><!-- Embedded -->
        </DataTemplate>
        <DataTemplate x:Key="StatusTemplateWarning" x:Name="mWarningImage">
            <Image Width="16" Height="16" Margin="3,0" Source="{Binding Converter={StaticResource ImagePathConverter}}" />
            <!--<Image Width="16" Height="16" Source="Images\Warning.png" />--><!-- Embedded -->
        </DataTemplate>
        <DataTemplate x:Key="StatusTemplateError" x:Name="mErrorImage">
            <Image Width="16" Height="16" Margin="3,0" Source="{Binding Converter={StaticResource ImagePathConverter}}" />
            <!--<Image Width="16" Height="16" Source="Images\Error.png" />--><!-- Embedded -->
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <wpftk:DataGrid Name="mDataGrid" ItemsSource="{Binding}" CanUserAddRows="False" IsReadOnly="True"></wpftk:DataGrid>
    </Grid>
</Window>

好的,现在我们应该完成了。

请确保创建 Images 文件夹并将图像添加到可执行文件运行的位置。您可能需要将 Images 文件夹添加到 debug 和 release 目录,或以其他方式解决此问题,否则在找不到图像时会引发异常。

 

 

© . All rights reserved.