继承和自定义WPF控件

本文关键字:控件 WPF 自定义 继承 | 更新日期: 2023-09-27 17:49:24

我们正在开发一个软件,旨在作为一个独立的工作,以及一个插件到不同的CAD程序。请注意,这意味着软件的离散版本。没有一个整体版本既可以作为插件又可以作为独立版本。为此,我们正在使用WPF开发一个接口。根据上下文(即,无论是独立版本还是连接到CAD程序),我希望能够改变外观,最重要的是界面的行为。我不希望重写整个界面。

我将简要概述我失败的想法,因为我希望它能为我想要实现的目标提供一些额外的背景。我最初的想法是创建一个项目,通过创建必要的控件并将它们组装到页面或窗口中的接口来定义默认接口。然后,如果我想定制接口以用于特定的CAD程序,我将继承控件和页面,并覆盖我想为给定上下文定制的部分。然而,我发现从WPF控件继承不是直截了当的。

我尝试的设置的快速模拟在这里列出。

默认视图包含一个名为DefaultUI的基本接口,收集在一个页面中。目前,它只包含一个自定义画布(称为DefaultCanvas)类型,包装在滚动查看器中。DefaultUI的XAML代码如下。

<Page x:Class="DefaultView.DefaultUI"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:DefaultView"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="DefaultUI">
    <Grid>
        <ScrollViewer HorizontalScrollBarVisibility="Auto">
            <local:DefaultCanvas x:Name="mCanvas" 
                         HorizontalAlignment="Stretch" 
                         VerticalAlignment="Stretch" Background="Transparent"
                         AllowDrop="True" IsHitTestVisible="True">
            </local:DefaultCanvas>
        </ScrollViewer>
    </Grid>
</Page>

我在CADView和StandAlone项目中尝试的是从DefaultCanvas和DefaultUI创建派生类,如CADViewCanvas和CADViewUI,并能够自定义这些行为。实际上,我主要想自定义画布的行为,但CADViewUI需要使用派生类而不是DefaultCanvas。我还想从DefaultUI派生的原因是,它可能包含几个控件,而我只想自定义一个。在这里,我意识到我可能有错误的想法,因为我假设mCanvas将被初始化为DefaultCanvas的实例时,CADViewUI调用它的基本构造函数。

CADViewCanvas中需要的附加功能是逻辑连接到所讨论的cad软件。在CADView中包含了一组包装器。每个包装器将模型中的一个对象连接到CAD软件中的一个对象。CADViewCanvas因此应该使用这个包装器,而不是直接在模型对象上工作。对模型对象执行相同的操作,但是还需要额外的逻辑来保持CAD对象是最新的。

继承和自定义WPF控件

当您想要调整派生类中的子控件时,继承包含子控件的控件可能会非常困难。

我建议只在基类中有可以通过样式定制的控件。对派生类中的子控件应用不同的样式是"简单"和干净的:只需定义一个新样式(可以基于默认样式)

当您需要控件的不同行为时,您需要以某种方式提供该行为:

  1. 将所有可能的行为放在基类中,并添加属性来打开和关闭它们,以便这些可以在样式中设置。这需要你事先知道什么是需要的,并且会产生臃肿的控制。我不建议这样做。
  2. 或者实现不同的控制。这意味着您不能将它们添加到基控件中,而必须将它们添加到派生控件中。我觉得干净多了。

简而言之:在所有派生类中不相同的功能不属于基类,所以不要把它放在基类中。如果它是简单的,视觉的东西,如布局/颜色/可见性样式可能是一个合适的解决方案。