0

我对 WPF 相当陌生,并且我对同一类型的所有控件的逻辑“分解”有疑问。

更准确地说,对于 Infragistics DataGrid 的任何实例,我都希望有一个带有“导出到 Excel”按钮的上下文菜单,而不必在每次使用所述网格时编写任何代码。此外,如果默认情况下我总是有一个“导出到 Excel”上下文菜单项,我还希望能够根据具体情况透明地添加更多项目。一个好处是能够删除特定实例上的“导出到 Excel”按钮。

我的问题是实现这一目标的最佳方法是什么:

  • 子类化 DataGrid 并在“OnInitialized”上以编程方式添加 ContextMenu?问题:我想在其中添加额外菜单项的网格怎么样... XAML 将覆盖已经存在的内容?此外,我不希望我的控件有子类,只需直接使用控件本身并使用 WPF 添加预期的行为。
  • 使用“行为”?我可以向这种类型的网格添加一个新的附加属性,但不确定这是否是一个好习惯
  • 还要别的吗?

我希望我的问题是有道理的!

注意:这个问题不是关于导出到 Excel,我知道用我的控件执行此操作的方法。

4

3 回答 3

0

我最终使用了附加属性解决方案。它非常干净,不会“污染”现有代码。您只需添加一行 XAML(见下文)即可将导出到 excel 功能添加到任何数据网格。

<igDP:XamDataGrid
                    x:Name="summary"
                    Behaviours:XamDataGridBehaviours.ExportFileName="plop.xls"
                    ActiveDataItem="{Binding Path=SelectedSummary}">
[...]
</igDP:XamDataGrid>

附加的属性代码本身如下:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Infragistics.Documents.Excel;
using Infragistics.Windows.DataPresenter;
using Infragistics.Windows.DataPresenter.ExcelExporter;
using Microsoft.Win32;

namespace MYCOMPANY.Plugin.Framework.Behaviours
{
    public class XamDataGridBehaviours
    {
        public static readonly DependencyProperty ExportFileNameProperty = DependencyProperty.RegisterAttached(
    "ExportFileName",
    typeof(string),
    typeof(XamDataGridBehaviours),
    new FrameworkPropertyMetadata(OnExportCommandChanged));

        private const string ExportToExcelHeader = "Export to Excel";

        [AttachedPropertyBrowsableForType(typeof(XamDataGrid))]
        public static string GetExportFileName(XamDataGrid d)
        {
            return (string)d.GetValue(ExportFileNameProperty);
        }

        public static void SetExportFileName(XamDataGrid d, string value)
        {
            d.SetValue(ExportFileNameProperty, value);
        }

        static void OnExportCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as XamDataGrid;
            var fileName = (string) e.NewValue;

            if (grid != null && !string.IsNullOrEmpty(fileName))
            {
                CreateExcelExportMenu(grid, fileName);
            }
            else if (grid != null && grid.ContextMenu != null)
            {
                SafeDeleteMenuItem(grid.ContextMenu);
            }
        }

        private static void CreateExcelExportMenu(XamDataGrid grid, string fileName)
        {
            var contextMenu = grid.ContextMenu ?? new ContextMenu();

            var exportToExcel = GetOrCreateMenuItem(grid, contextMenu, fileName);

            contextMenu.Items.Add(exportToExcel);

            grid.ContextMenu = contextMenu;
        }

        private static void ExportToExcel(XamDataGrid grid, string fileName)
        {
            var saveFileDialog = new SaveFileDialog();
            saveFileDialog.FileName = fileName;
            saveFileDialog.DefaultExt = ".xls";
            saveFileDialog.Filter = "Excel spreadsheets (.xls)|*.xls";

            if (saveFileDialog.ShowDialog() == true)
            {
                var exporter = new DataPresenterExcelExporter();
                exporter.Export(grid, saveFileDialog.FileName, WorkbookFormat.Excel97To2003);
            }
        }

        private static MenuItem GetOrCreateMenuItem(XamDataGrid grid, ContextMenu menu, string fileName)
        {
            foreach (var item in menu.Items)
            {
                if (item is MenuItem)
                {
                    var menuitem = item as MenuItem;
                    if (menuitem.Header.ToString() == ExportToExcelHeader)
                    {
                        menuitem.Command = new RelayCommand(o => ExportToExcel(grid, fileName));
                        return menuitem;
                    }
                }
            }

            var exportToExcel = new MenuItem();
            exportToExcel.Header = ExportToExcelHeader;
            exportToExcel.Command = new RelayCommand(o => ExportToExcel(grid, fileName));

            var icon = new Image();
            var bmImage = new BitmapImage();
            bmImage.BeginInit();
            bmImage.UriSource = new Uri(@"..\..\Images\excel.png", UriKind.RelativeOrAbsolute);
            bmImage.EndInit();
            icon.Source = bmImage;
            icon.MaxWidth = 16;
            exportToExcel.Icon = icon;

            return exportToExcel;
        }

        private static void SafeDeleteMenuItem(ContextMenu menu)
        {
            MenuItem toDelete = null;

            foreach (var item in menu.Items)
            {
                if (item is MenuItem)
                {
                    var menuitem = item as MenuItem;
                    if (menuitem.Header.ToString() == ExportToExcelHeader)
                    {
                        toDelete = menuitem;
                        break;
                    }
                }
            }

            if (toDelete != null)
                menu.Items.Remove(toDelete);
        }
    }
}

如您所见,每当我们为网格设置一个非空的导出文件名时,代码都会添加一个导出到 excel 项。如果文件名最终为 null,则代码将尝试删除导出项(如果存在)。这样,它不应该阻止 xaml 设置其他项目,并且应该保持透明。

于 2012-07-31T09:23:27.040 回答
0

在您的数据网格控件中创建一个List<MenuItem> DependencyProperty(如果您想从. 并在事件中将这些附加到 Common MenuItems。我希望这会有所帮助。ViewModelmenuItemsevent DataGridLoadedmenuItems

于 2012-07-31T08:39:42.227 回答
0

如果您在 XAML 中执行此操作,则可以执行以下操作:

<DataGrid>
  <DataGrid.ContextMenu>
     <!--Binding to your view model and the command is whatever your command name should be ->
     <MenuItem Header="Export to CSV" Command="{Binding Export}"/>
  </DataGrid.ContextMenu>
</DataGrid>

这允许您将新对象添加到上下文菜单。

于 2012-07-31T11:04:51.087 回答