[英]How to implement custom interfaces in WPF UserControl and avoid dynamic casts?
我有几个 WPF UserControl。 这些控件中的每一个都实现了一个接口IStepEditor
类声明如下:
public partial class EditorLoadCsv : UserControl, IStepEditor { ... }
IStepEditor
不是很重要,但目前定义如下:
public interface IStepEditor
{
StepConfig Save();
void Load(StepConfig config);
}
然后我有几个类持有这些控件,如下所示:
public class StepConfigController
{
public IStepEditor EditorControl { get; }
}
当我到处使用IStepEditor
时,所有这些都按预期工作,但是要将这些控件从 StepConfigController 添加到 WPF 窗口,我最终必须将它们转换为UserControl
,如下所示:
((StackPanel)panEditorControl).Children.Add(currentControl as UserControl);
由于 IStepEditor 实现实际上是一个 UserControl,它可以工作。 我可以为该演员添加检查,但整个想法似乎是错误的。 我通过一些我相信其他人会遵循的弱关系将一个对象投射到另一个非常不相关的对象上。
我试图创建一个继承自UserControl
和IStepEditor
的抽象类,并从中派生出我的实际UserControl
,但由于 WPF UserControl
是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 标记从UserControl
更改为StepEditorControl
失败,但它可能是整个问题的正确解决方案。 我还尝试实现一个 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-首先如何重构代码以避免这种丑陋?
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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.