继承用户控件以使用不同的子控件

3
我有一个用户控件,名为GridMasterControl,其中包含了另外一个控件Grid(除其他之外)。
现在我需要继承自Grid以创建EditableGrid(以添加编辑功能到网格)。
然后我需要创建一个EditableGridMasterControl,它将与GridMasterControl完全相同,只不过使用的是EditableGrid而非Grid
我可以想到两种实现方式,但都有问题:
1. 我可以复制和粘贴GridMasterControl,仅将Grid更改为EditableGrid。这样做不好(代码重复不好)。
2. 我可以让EditableGridMasterControl继承GridMasterControl,然后在GridMasterControl中添加一个虚拟函数CreateGridEditableGridMasterControl可以实现该函数以创建EditableGrid控件。这也是非常糟糕的想法,因为我需要更改设计器文件来创建控件。我需要保持设计器文件的清晰干净。
我应该如何最好地实现这个目标?
编辑:为了澄清,我认为问题的关键是Visual Studio不允许修改它所创建的设计器文件(或者至少这样做是非常糟糕的),我希望能够有条件地创建不同的类,具体取决于情况。
4个回答

4

你是否可以创建一个控件,EditableGridMasterControl,它有一个 ReadOnly 属性?如果将其设置为 true,则禁用编辑。这样只需要维护一个控件集合,但需要更高级的控件,而不是简单的 GridMasterControl


我本来希望避免这种情况,因为我们只需要在一个地方使用可编辑网格,并且需要编写很多(有些相当hacky的)代码才能使其可编辑。 - Mongus Pong
1
如果你真的想避免使用可编辑网格,那么你可以将其包装在另一个控件中,根据只读设置公开其中的两个之一。但通常情况下,尽可能保持代码量最少是最好的选择,即使它有些hackish。 - Rune Grimstad
我能想到的唯一方法是在构造函数中创建两个控件,然后根据设置显示/隐藏相关控件。两个网格仍将保留在内存中。虽然我认为这不是一个好主意,因为必须传递所有属性/方法,但我仍然很好奇你会如何做到这一点。 抱歉,我还没有完全理解...可能是因为今天早上被愚蠢的棍子打了一下。 - Mongus Pong
@Fungus - 你不应该维护单独的“Grid”和“EditableGrid”控件。将只读功能构建到“EditableGrid”中(通过父级上的“ReadOnly”属性激活),使用它,并删除基本的“Grid”类。 - Jeff Sternal
@Jeff,我觉得我的命名可能有点误导。把它们想象成Grid和HackedAboutLikeHellToGetATinyPieceOfFunctionalityWeWillRarelyUseGrid。:) 我真的不想这样做。 - Mongus Pong
实际上,你还可以做一件事。让你的控件默认为只读网格,但让该网格包含在一个面板控件中。现在,在你的EditableGrid中,你可以在构造函数中添加代码,在调用InitializeComponent之后添加代码。这段代码通过清除面板的Controls集合来移除只读网格,然后添加EditableGrid。你将不得不手动添加事件处理程序,但它应该能够“正常”工作。 - Rune Grimstad

3
也许你可以考虑使用组合模式来在不同的控件之间重用共同的功能。 组合模式是一种常见的设计模式,它允许您将多个对象组合成一个更大的对象,并以统一的方式处理它们。

1
如果您想让设计文件对两者保持相同,请尝试以下方法:不要将实际的网格控件放置到GridMasterControl中,而是放置一个面板作为占位符。
然后创建一个强制初始化步骤,在其中创建适当的网格对象(使用像IGrid这样的接口)。这可以在派生类中完成。
这就是我的意思,当然您可以以几种不同的方式实现相同的模式。AbstractGridMasterControl的具体实现之间共享的代码量可能会有所不同,这取决于控件的相似程度(我不知道)。您可以使用父类代替接口IGrid - 再次取决于您想如何进行继承。
interface IGrid {...}
class Grid : IGrid { ...}
class EditableGrid : IGrid { ... }

abstract class AbstractGridMasterControl
{
    protected IGrid Grid
    {
        set { this.panelControl.Controls.Add(value as Control);}
    }
}

class GridMasterConrol : AbstractGridMasterControl
{
    public GridMasterControl()
    {
        this.Grid = new Grid();
    }
}

class EditableGridMasterConrol : AbstractGridMasterControl
{
    public GridMasterControl()
    {
        this.Grid = new EditableGrid();
    }
}

不错,我喜欢你的思考方式,先生!但问题在于它确实会使用额外的窗口句柄,但迄今为止这是最干净的代码。 - Mongus Pong

0

如果GridMasterControl对于任何网格类都在执行相同的操作,则无需更改任何内容: GridMasterControlGrid成员可以保存一个EditableGrid


我该怎么做?“this.Grid = new Common.Framework.UI.Controls.Grid();”在设计文件中。我不能更改这一行。 - Mongus Pong
那么你如何确定使用哪种类型的网格呢? - Matt Ellen
如果网格位于批量输入屏幕上,它应该是可编辑网格。在应用程序的其他位置,它将是普通网格。我需要解决如何使代码干净地实现这一点。 :) - Mongus Pong
因此,在一个批量输入屏幕中,给它一个具有可编辑网格的GridMasterControl,在所有其他屏幕中都给它一个网格。 - Matt Ellen
这就是我想做的事情,只是我不知道该怎么做。在GridMasterControl的设计文件中,它创建了一个Grid。我如何才能有条件地创建EditableGrid(同时仍然允许我们在VS设计器中调整布局)? - Mongus Pong
你每个屏幕都有不同的GridMasterControl吗?如果是这样,您可以编辑需要可编辑网格的一个屏幕的设计师代码。 - Matt Ellen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接