创建自定义WPF控件时应该使用什么方法?

时间:2011-04-25 10:54:16

标签: wpf data-binding custom-controls

我要将旧的WinForms应用程序重做为WPF应用程序。该应用程序的核心是自定义“网格”组件。我想了解一下作为WPF组件的最佳方法。

应用程序显示不同国家/部门的数据网格。网格的每个单元格根据该国家/部门的可用数据显示不同的信息(例如图形,图像)。

我有一个我希望保持清洁的域模型程序集 - 以最大限度地重用。结构如下:

    • 国家
    • 部分
    • 数据[国家,部门]

网格显示左下角的国家和顶部的扇区。

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

一切正常。

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

此外,WinForms组件是完全自定义绘制的 - 没有使用子控件(例如标签)。使用WPF用户控件并从GridLayout和许多Label,Shape等控件构建表会更好吗?在实践中,它们可能在网格中有20行和20列,并且用户在使用应用程序时会定期删除并添加国家/扇区(行/列)。

我的直接目标是确保我的设计在WPF生态系统中发挥出色,但我的第二个目标是学习如何以WPFy方式做事 - 鉴于这是我的第一个WPF应用程序。我非常关注构建一个普通的WPF应用程序 - 它只是自定义控件的东西仍然有点模糊(甚至在阅读它之后)。

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

1 个答案:

答案 0 :(得分: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... 
}