【问题标题】:What approach should I use when creating a custom WPF control?创建自定义 WPF 控件时应该使用什么方法?
【发布时间】:2011-04-25 10:54:15
【问题描述】:

我将重做一个旧的 WinForms 应用程序作为 WPF 应用程序。这个应用程序的核心是一个自定义的“网格”组件。我想了解作为 WPF 组件执行此操作的最佳方式的一些想法。

应用程序显示不同国家/部门的数据网格。网格的每个单元格显示不同的信息(例如图表、图像),具体取决于该国家/部门的可用数据。

我有一个域模型程序集,我想保持干净 - 以最大限度地重用。结构如下:

    • 大陆
    • 国家/地区
    • 行业
    • 数据[国家、部门]

网格在左侧显示国家,在顶部显示部门。

在当前应用程序中,网格组件有一个 (POCO) Table 属性和一个 Refresh() 方法来手动重绘它。因此,如果 Table 更新,则网格组件的父级会刷新它。如果单击大陆、国家或单元格,网格组件还会触发许多事件 - 以便父级可以通过弹出菜单等进行响应。

这一切都很好。

但是,我想知道这是否是用于 WPF 应用程序的正确模型。查看许多 WPF 示例,它们支持数据绑定等。但是,从简单的示例中,尚不清楚我如何将复杂的对象绑定到我的组件 - 或者它是否值得。

此外,WinForms 组件是完全自定义绘制的 - 没有使用子控件(例如标签)。使用 WPF 用户控件并从 GridLayout 和大量标签、形状等控件构建表格会更好吗?实际上,它们在网格中可能是 20 行和 20 列,用户在使用应用程序时经常删除和添加国家/部门(行/列)。

我的近期目标是确保我的设计在 WPF 生态系统中运行良好,但我还有一个次要目标是学习如何以 WPFy 方式做事 - 因为这是我的第一个 WPF 应用程序。我非常了解构建通用 WPF 应用程序的使用 - 它只是自定义控件的东西仍然有点模糊(即使在阅读了一点之后)。

任何见解/指导将不胜感激。

【问题讨论】:

  • 现有控件的图像会有所帮助。

标签: wpf data-binding custom-controls


【解决方案1】:

您肯定希望采用 MVVM 方法,例如 outlined by Josh Smith。实际上,这意味着您的自定义网格组件将包含在它自己的视图中。支持视图将是您的 ViewModel,您将在其中定义包含数据的对象的 ObservableCollection。这些对象可能来自您的模型。这种交互如下图所示:

型号:

public class TableData
{
    public string Country { get; set; }
    public string Continent { get; set; }
    public object Sector { get; set; }
}

public class TableManager : ITableManager
{
    public Collection<TableData> Rows;

    public void GetData()
    {
        this.Rows = new Collection<TableData>();
        this.Rows.Add(...
    }
}

视图模型:

public class TableViewModel
{
    private ITableManager _tableManager;

    public TableViewModel() : base(new TableManager())
    {
    }

    // for dependency injection (recommended)
    public TableViewModel(ITableManager tableManager)
    {
        _tableManager = tableManager;
        _tableManager.GetData();
    }

    public ObservableCollection<TableData> Rows
    { 
        get { return _tableManager.Rows; }
    }
}

查看:

<ctrls:CustomDataGrid
    ItemsSource={Binding Rows}
    AutoGenerateColumns=True
    >
    <!-- Use AutoGenerateColumns if the # of sectors is dynamic -->
    <!-- Otherwise, define columns manually, like so: -->
    <DataGridTextColumn
         Width="*"
         Header="SectorA"
         Binding="{Binding Country}
         />
</ctrls:CustomDataGrid>

我在视图中使用了CustomDataGrid,因为我假设您要将自己的DataGrid 子类化。这将允许您覆盖事件以根据自己的喜好自定义 DataGrid:

public class CustomDataGrid : DataGrid
{
    public override Event... 
}

【讨论】:

    猜你喜欢
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多