0

我有几个 WPF 用户控件。这些控件中的每一个都实现了一个接口IStepEditor

类声明如下:

 public partial class EditorLoadCsv : UserControl, IStepEditor { ... }

IStepEditor不是很重要,但目前定义如下:

public interface IStepEditor
{
    StepConfig Save();
    void Load(StepConfig config);
}

然后我有几个类持有这些控件,如下所示:

public class StepConfigController
{
    public IStepEditor EditorControl { get; }
}

当我使用 all around 时,所有这些都按预期工作IStepEditor,但是要将这些控件从 StepConfigController 添加到 WPF 窗口,我最终必须将它们强制转换为UserControl,如下所示:

((StackPanel)panEditorControl).Children.Add(currentControl as UserControl);

由于 IStepEditor 实现实际上是一个用户控件,因此它可以工作。我可以为该演员添加检查,但整个想法似乎是错误的。我通过一些我相信其他人会遵循的弱关系将一个对象投射到另一个非常不相关的对象。

我试图创建一个继承自两者的抽象类UserControlIStepEditor并让我的实际UserControls 从中派生,但由于 WPFUserControl是 s partial classes,所以它不起作用。是这样的:

public abstract class StepEditorControl : UserControl, IStepEditor
{
    abstract public StepConfig Save();
    abstract public Load(StepConfig config);
}

所以这个类是合法和编译的,但试图在 WPF 中派生它失败了。

public partial class EditorLoadCsv : StepEditorControl
{
}

此代码生成:

error CS0263: Partial declarations of 'EditorLoadCsv' must not specify different base classes

这是正确的,因为 xaml 标记仍然引用UserControl. 尝试将 xaml 标记从失败更改UserControlStepEditorControl失败,但这可能是整个问题的正确解决方案。我也尝试实现一个 WPF 自定义控件库,但是仅仅实现一个具有 2 个方法的接口似乎需要做很多工作。

XAML 是通过 Visual Studio 设计器自动生成的:

<UserControl x:Class="MyNamespace.EditorLoadCsv"
             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:MyNamespace"
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="623.077">

<!--- Actual UserControl content ---!>

</UserControl>

因此,对这些问题中的任何一个的答案都可以解决我的问题:

1- 使用自定义接口实现 WPF UserControl 时如何避免(可能)危险的动态转换?
2- 如何让 WPF XAML 标记接受自定义类而不是 UserControl?
3-首先如何重构代码以避免这种丑陋?

4

1 回答 1

1

Panel.Children属性是 UIElementCollection,因此应添加的任何内容都必须是 UIElement,它是所有 WPF UI 组件的基类。

不要使用as运算符,而只是将编辑器对象转换为 UIElement。如果其中任何一个偶然不是 UIElement,您将正确获得InvalidCastException.

((Panel)panEditorControl).Children.Add((UIElement)currentControl);

为了为您的所有 StepEditor 创建一个 UserControl 派生的基类,您正确地完成了第一步:

public abstract class StepEditorControl : UserControl, IStepEditor
{
    public abstract void Load(StepConfig config);
    public abstract StepConfig Save();
}

但是,从 StepEditorControl 派生的控件的 XAML 必须如下所示:

<local:StepEditorControl
    x:Class="MyNamespace.EditorLoadCsv"
    xmlns:local="clr-namespace:MyNamespace"
    ...>
    ...
</local:StepEditorControl>
于 2019-11-23T17:01:45.320 回答