为什么WPF中许多属性是“对象”而不是接口?

10

我可能在WPF设计的基础知识方面有所遗漏,但是我想知道为什么许多WPF控件的属性都以类型“Object”的形式公开?

例如,MenuItem.Icon 是一个 Object,MenuItem.ToolTip 也是。作为一个几乎是第一次使用者,这让我感到非常困惑(感觉自己正在使用动态编程语言,不知道将 ToolTip 设置为 String 类型是否会有效)。此外,我试图将 Icon 设置为“System.Drawing.Icon”,但我得到了一个 ArgumentException,上面写着“参数‘picture’必须是可用作图标的图片”。难道属性不应该被分类,以便至少能描述你应该给它什么吗?

老实说,我猜测原因是你不能在你没有创建的类型上实现一个接口(除非创建一个包装器),但这只是一个猜测。

非常感谢您提供的答案和见解!

3个回答

2
在我看来,主要原因是由于Object是".Net Framework"中所有类的"终极基类",这为你提供了灵活性,在WPF中,你不会被限制在预定义类型上。WPF与其他技术不同并且需要一定的学习曲线,但它确实提供了更多的选项来创建一个外观漂亮的产品。
例如,你可以将一个TextBox分配给ToolTip:
TextBox tb = new TextBox();
tb.Text = "Hello World";
this.ToolTip = tb;

一张位图。
BitmapImage myBitmapImage = new BitmapImage(new Uri((@"C:\Temp\20100706.jpg")));
Image image = new Image();
image.Source = myBitmapImage;
this.ToolTip = image;

给菜单项分配图像

BitmapImage myBitmapImage = new BitmapImage(new Uri((@"C:\Temp\20100706.jpg")));
Image image = new Image();
image.Source = myBitmapImage;
menuItem1.Icon = image;

我认为这很酷,但对象不是必须是某种UI元素吗?TextBox和Image都是FrameworkElement。我看到的唯一可以分配的不是FrameworkElement的东西是String...那真的是唯一的东西吗?如果是的话,似乎不是一个好的理由让它成为“Object”,因为我可以只创建一个Label或包装器来包装我的String。 - Trevor Sundberg
@Rovert 不是的,这取决于属性,如果它有视觉方面并且WPF可以将其转换为图像,则会显示。您可以将任何内容分配给对象。我认为这是使Xaml标记工作所需的TypeConversion的副产品。 - Mark Hall
TypeConversion 的有趣之处在于它决定可以显示的内容,这实际上更加合理。例如,查找 ImageSource 来确定其工作原理会导致巨大的混乱,但现在我知道幕后一定存在某些动态行为。谢谢! - Trevor Sundberg
这个概念的一部分是,许多情况下,当WPF允许您传递一个对象时,它足够灵活,以知道“这是一个实际的控件,我可以显示”或“这是一个我不知道的类型,但我会尝试找到一个DataTemplate来知道如何可视化它”。其中一些例子包括ItemsControl和ItemTemplate、ContentControl和ContentTemplate。还有几种情况也适用于此。 - dowhilefor
这就是DataTemplates的用途! - Trevor Sundberg

1
例如,考虑 ToolTip。 ToolTip 是一个 ContentControl,它可以包含任何类型的 CLR (Common Language Runtime) 对象(例如字符串或 DateTime 对象)或 UIElement 对象(例如矩形或面板)。这使您能够向 Button 和 CheckBox 等控件添加丰富的内容。
因此,像 ToolTip 这样的元素被公开为 Object,即类型层次结构的根(从而实现了易用性、灵活性和代码清晰度)。

0

想象一下,如果这些属性被定义为UIElements(或其他WPF特定对象),那么你如何向控件添加不是UIElements的对象?

你需要提供一个从WPF对象派生的包装器,以公开所需的信息。大多数情况下,包装器只需调用被包装对象的ToString()方法即可。由于大多数类型都提供了足够好的ToString()默认实现,因此最好直接调用它,而不是让开发人员为每个对象编写包装器。

其次,想象一下如果它们被定义为某个接口。如果你想传达某些接口无法处理的信息怎么办?唯一的选择是(a)开发人员接受框架的限制或(b)Microsoft更新接口并破坏所有已经编写的现有代码。

还要考虑一下,如果你正在使用像MVVM这样的模式。当前的设计意味着你的视图模型可以公开与WPF无关的属性,这最终使你的代码在不同技术之间更具可重用性。

最后,请记住,表示属性的对象和WPF呈现信息的方式之间存在差异。例如,如果您使用像System.String这样的基元类型,WPF将创建一个文本块并将文本属性设置为ToString()的结果。这允许UI显示的数据与UI 渲染信息的方式之间有非常清晰的分离。

以表示菜单项的简单类为例:

public class MenuItem
{
    public string Text { get; set; }
    public bool IsChecked { get; set; }
    public bool IsEnabled { get; set; }
}

这种类型仅公开有关菜单项的数据,没有关于如何呈现此信息的信息。实际上,除了类的名称(MenuItem)之外,它甚至不特定于菜单项,相同的数据可以在另一个 UI 控件中使用,例如无需更改的选中列表框。如果该类公开了 WPF 特定的用户界面元素,则需要为每个不同的用户界面控件调整信息。


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