WPF 面试题及答案






4.54/5 (129投票s)
在本节中,我们将介绍 .NET 面试中经常出现的 WPF 重要面试题。我知道这个列表不完整,但至少想从一些内容开始,然后随着时间的推移不断添加。
引言
什么是 WPF?
既然已经有了 Windows Forms,为什么还需要 WPF?
WPF 中的 XAML 是什么?为什么我们需要它?
XAML 文件中的 xmlns 是什么?
WPF 中 xmlns 和 xmlns:x 的区别是什么?
请举例说明在 XAML 中使用“xmlns:x”命名空间的情况?
什么时候应该使用“x:name”而不是“name”?
WPF 中有哪些不同类型的控件?
你能解释一下完整的 WPF 对象层次结构吗?
这是否意味着 WPF 已经取代了 DirectX?
那么 XAML 只适用于 WPF 吗?
你能解释一下 WPF 的总体架构吗?
WPF 项目中的 App.xaml 是什么?
WPF 中有哪些不同的对齐方式?
WPF 中的资源是什么?
解释静态资源和动态资源的区别?
什么时候应该使用静态资源而不是动态资源?
解释绑定和命令的必要性?
解释单向、双向、一次性以及单向到源?
你能用一个例子解释 WPF 命令吗?
“UpdateSourceTrigger”如何影响绑定?
解释“INotifyPropertyChanged”接口的必要性?
WPF 中的值转换器是什么?
解释 WPF 中的多重绑定和多值转换器?
解释 WPF 相对绑定/相对资源?
使用相对源进行绑定的不同方式有哪些?
你能解释 WPF 中的自相对源绑定吗?
解释 WPF 中的祖先相对源绑定?
解释 WPF 中可视化树和逻辑树的区别?
为什么我们需要在 WPF 中拥有可视化树和逻辑树的概念?
解释 WPF 中的路由事件?
WPF 中的样式是什么?
什么是样式触发器?
什么是 MVVM?
MVVM 的好处是什么?
命令和绑定在 MVVM 模式中有什么重要性?
MVVM 和三层架构的区别是什么?
解释委托命令?
什么是 PRISM?
PRISM 的好处是什么?
各个单元如何组合成一个单元?
PRISM 实现 MVVM 吗?
PRISM 是 WPF 的一部分吗?
什么是 Expression Blend?
我在 CodeProject 上的其他面试题文章
引言
在本节中,我们将介绍 .NET 面试中经常出现的 WPF 重要面试题。我知道这个列表不完整,但至少想从一些内容开始,然后随着时间的推移不断添加。
如果您认为我应该涵盖更多问题,请在下面的评论中输入问题。
祝您求职愉快 。
什么是 WPF?
WPF(Windows Presentation Foundation)是一个用于在 Windows 应用程序中显示用户界面、文档、图像、电影等的图形子系统。
既然已经有了 Windows Forms,为什么还需要 WPF?
Remember: - ABCDEFG
A - 随处执行 (Windows 或 Web)
B - 绑定 (更少的编码)
C - 统一外观 (资源和样式)
D - 声明式编程 (XAML)
E - Expression Blend 动画 (动画轻松)
F - 快速执行 (硬件加速)
G - 图形硬件独立 (分辨率独立)
我强烈建议您观看下面的视频,它将实际解释上述 A 到 G 的所有要点。

WPF 中的 XAML 是什么?为什么我们需要它?
XAML 是一个 XML 文件,它表示你的 WPF UI。在 XML 中创建 UI 表示的全部意义在于一次编写,随处运行。因此,相同的 XAML UI 可以通过 WPF 呈现为 Windows 应用程序,也可以通过 WPF 浏览器或 Silverlight 应用程序在浏览器中显示。
XAML 文件中的 xmlns 是什么?
“xmlns”代表 XML 命名空间。它有助于我们避免 XML 文档中的名称冲突和混淆。例如,考虑下面的两个 XML,它们都有 table 元素,一个 table 是 HTML 表格,另一个代表餐厅的桌子。现在,如果这两个元素出现在一个 XML 文档中,就会出现名称冲突和混淆。
<table>
<tr>Row1
Row2
===============================
red Tea
因此,为了避免同样的情况,我们可以使用 XML 命名空间。您可以在下面的 XML 中看到,我们已经用“
<h:table xmlns:h="http://www.w3.org/TR/html4/">
<tr>Row1
Row2
================================
red
Tea
WPF 中 xmlns 和 xmlns:x 的区别是什么?
这两个命名空间都有助于定义/解析 XAML UI 元素。
第一个命名空间是默认命名空间,用于解析所有 WPF 元素。
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
第二个命名空间以“x:”为前缀,用于解析 XAML 语言定义。
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
例如,对于下面的 XAML 片段,我们有两件事,一个是“StackPanel”,另一个是“x:name”。“StackPanel”由默认命名空间解析,“x:name”通过“xmlns:x”命名空间解析。
<StackPanel x:Name="myStack" />
请举例说明在 XAML 中使用“xmlns:x”命名空间的情况?
我们使用“xmlns:x”命名空间有两种常见情况:-
使用“x:class”属性为 XAML 文件定义后台代码。
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="MyNamespace.MyCanvasCodeInline" >
其次,为元素提供名称。
<StackPanel x:Name="myStack" />
什么时候应该使用“x:name”而不是“name”?
“x:name”和“name”没有区别,“name”是“x:name”的简写。但在那些找不到“name”属性的类中(这种情况很少见),我们需要使用“x:name”属性。
WPF 中有哪些不同类型的控件?
WPF 控件可以分为四类:-
- Control:- 这是您大部分时间都会使用的基本控件。例如文本框、按钮等。现在,像按钮、文本框、标签等独立控件被称为内容控件。还有其他可以容纳其他控件的控件,例如项目控件。项目控件可以包含多个文本框控件、标签控件等。
- Shape:- 这些控件帮助我们创建简单的图形控件,如椭圆、线条、矩形等。
- Panel:- 这些控件有助于对齐和定位控件。例如,网格帮助我们以表格方式对齐,堆栈面板帮助进行水平和垂直对齐。
- Content Presenter:- 此控件有助于在其内部放置任何 XAML 内容。当我们想要在 WPF 屏幕上添加动态控件时使用。
所有上述四种 WPF 控件最终都继承自 WPF 的 FrameworkElement 类。
你能解释一下完整的 WPF 对象层次结构吗?
Object:- 由于 WPF 是使用 .NET 创建的,所以 WPF UI 类继承的第一个类是 .NET 的 Object 类。
Dispatcher:- 此类确保所有 WPF UI 对象只能由拥有它的线程直接访问。不拥有它的其他线程必须通过 Dispatcher 对象访问。
Dependency:- WPF UI 元素使用 XAML(XML 格式)表示。在任何给定时刻,WPF 元素都被其他 WPF 元素包围,周围的元素可以影响这个元素,这要归功于这个 Dependency 类。例如,如果一个文本框被一个面板包围,面板的背景颜色很可能会被文本框继承。
Visual:- 这个类帮助 WPF UI 拥有它们的视觉表现。
UI Element:- 这个类有助于实现事件、输入、布局等功能。
Framework Element:- 这个类支持模板、样式、绑定、资源等。
最后,所有 WPF 控件,如文本框、按钮、网格以及你能从 WPF 工具箱中想到的任何东西,都继承自 FrameworkElement 类。
这是否意味着 WPF 已经取代了 DirectX?
不,WPF 不会取代 DirectX。DirectX 仍然需要用于制作尖端游戏。DirectX 的视频性能仍然比 WPF API 高很多倍。因此,在游戏开发方面,首选永远是 DirectX 而不是 WPF。WPF 不是制作游戏的最佳解决方案,哦,是的,你可以制作一个井字游戏,但不能制作高动作动画游戏。
要记住的一点是,WPF 是 Windows Forms 的替代品,而不是 DirectX。
那么 XAML 只适用于 WPF 吗?
不,XAML 不仅仅适用于 WPF。XAML 是一种基于 XML 的语言,它有各种变体。
WPF XAML 用于描述 WPF 内容,例如 WPF 对象、控件和文档。在 WPF XAML 中,我们还有 XPS XAML,它定义了电子文档的 XML 表示。
Silverlight XAML 是 WPF XAML 的子集,用于 Silverlight 应用程序。Silverlight 是一种跨平台浏览器插件,可帮助我们创建具有二维图形、动画以及音频和视频的丰富 Web 内容。
WWF XAML 帮助我们描述 Windows Workflow Foundation 内容。WWF 引擎然后使用此 XAML 并相应地调用工作流。
你能解释一下 WPF 的总体架构吗?
上图展示了 WPF 的整体架构。它有三个主要部分:Presentation Core、Presentation Framework 和 Milcore。在同一张图中,我们还展示了其他部分(如 DirectX 和操作系统)如何与系统交互。因此,让我们逐节了解每个部分的工作原理。
User32:- 它决定了屏幕上的内容去向。
DirectX:- 如前所述,WPF 内部使用 DirectX。DirectX 与驱动程序通信并渲染内容。
Milcore:- Mil 代表媒体集成库。此部分是非托管代码,因为它充当 WPF 托管 API 和 DirectX/User32 非托管 API 之间的桥梁。
Presentation Core:- 这是 WPF 公开的低级 API,提供 2D、3D、几何等功能。
Presentation Framework:- 此部分包含高级功能,如应用程序控件、布局、内容等,可帮助您构建应用程序。
WPF 项目中的 App.xaml 是什么?
App.xaml 是启动文件或引导程序文件,它从 WPF 项目中触发您的第一个 XAML 页面。
WPF 中有哪些不同的对齐方式?
WPF 中有五种对齐方式:-
Grid:- 在 Grid 对齐中,我们将屏幕划分为像 HTML 表格一样的静态行和列,并将元素放置在这些行和列区域中。
<Grid>
<Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Background="Red">1st column 1st row </Label>
<Label Grid.Column="1" Grid.Row="0" Background="LightGreen">2nd Column 2nd row</Label>
<Label Grid.Column="0" Grid.Row="1" Background="Red">1st column 2nd row</Label>
<Label Grid.Column="1" Grid.Row="1" Background="LightGreen">2nd Column 2nd row</Label>
StackPanel:- 以垂直或水平格式排列控件。
<StackPanel Orientation="Vertical">
<Label Background="Red">Red </Label>
<Label Background="LightGreen">Green </Label>
<Label Background="LightBlue">Blue </Label>
<Label Background="Yellow">Yellow </Label>
WrapPanel:- 将元素排列成一行,直到达到边界,然后换行到下一行。
<WrapPanel Orientation="Horizontal">
<Label Width="125" Background="Red">Red 1</Label>
<Label Width="100" Background="LightGreen">Green 1</Label>
<Label Width="125" Background="LightBlue">Blue 1</Label>
<Label Width="50" Background="Yellow">Yellow 1</Label>
<Label Width="150" Background="Orange">Orange 1</Label>
<Label Width="100" Background="Red">Red 2</Label>
<Label Width="150" Background="LightGreen">Green 2</Label>
<Label Width="75" Background="LightBlue">Blue 2</Label>
Dock Panel:- 将控件对齐到五个不同区域:上、下、左、右和中心。
<DockPanel>
<Label DockPanel.Dock="Top" Height="100" Background="Red">Top 1</Label>
<Label DockPanel.Dock="Left" Background="LightGreen">Left</Label>
<Label DockPanel.Dock="Right" Background="LightCyan">Right</Label>
<Label DockPanel.Dock="Bottom" Background="LightBlue">Bottom</Label>
Demo of Dock panel
Canvas:- 使用坐标绝对定位元素。
<Canvas Margin="273,130,144,99">
<TextBlock> Canvas position
</Canvas>
WPF 中的资源是什么?
资源是在 WPF XAML 中引用的对象。在 C# 代码中,当我们创建对象时,我们执行以下三个步骤:-
using CustomerNameSpace; // import the namespace.
Customer obj = new Customer(); // Create object of the class
Textbox1.text = obj.CustomerCode; // Bind the object with UI elements
因此,即使在 WPF XAML 中定义资源(也就是对象),我们也需要执行上述 3 个步骤:-
- 导入类所在的命名空间:- 要定义命名空间,我们需要使用“xmlns”属性,如下面的 XAML 代码所示。
<Window x:Class="LearnWpfResources.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:custns="clr-namespace:LearnWpfResources" Title="MainWindow" Height="350" Width="525">
- 创建类的对象:- 要在 XAML 中创建类的对象,我们需要使用 resource 标签创建一个资源,如下面的代码所示。您可以看到对象名称是“custobj”。
<Window.Resources> <custns:Customer x:Key="custobj"/> </Window.Resources>
上面的代码可以映射到 C# 中的类似内容:
Customer custobj = new Customer();
- 将对象与 UI 对象绑定:- 创建对象后,我们可以使用绑定(如单向、双向)将它们绑定起来,如上面解释的“解释单向、双向、一次性以及单向到源?”问题。
<TextBox Text="{Binding CustomerCode, Mode=TwoWay, Source={StaticResource custobj}}" />
解释静态资源和动态资源的区别?
资源可以静态或动态引用。静态引用的资源只评估一次,之后如果资源发生更改,这些更改不会反映在绑定中。而动态引用的资源在每次需要时都会进行评估。
考虑下面将“SolidColorBrush”资源设置为“LightBlue”颜色的情况。
<Window.Resources>
<SolidColorBrush Color="LightBlue" x:Key="buttonBackground" />
上述资源分别以静态和动态方式绑定到以下两个文本框。
<TextBox Background="{DynamicResource buttonBackground}" /> <textbox background="{StaticResource buttonBackground}">
现在,如果我们修改资源,您会看到第一个文本框的背景颜色发生变化,而另一个文本框的颜色保持不变。
private void Button_Click(object sender, RoutedEventArgs e) { Resources["buttonBackground"] = Brushes.Black; }
下面是相同的输出。
什么时候应该使用静态资源而不是动态资源?
动态资源会降低应用程序性能,因为它们在每次需要时都会进行评估。因此,最佳实践是使用静态资源,除非有特定原因需要使用动态资源。如果您希望资源反复评估,那么才使用动态资源。
解释绑定和命令的必要性?
WPF 绑定有助于在 WPF 对象之间发送/接收数据,而命令则有助于发送和接收操作。发出数据或操作的对象称为源,希望接收数据或操作的对象称为目标。
解释单向、双向、一次性以及单向到源?
以上所有 4 点定义了应用 WPF 绑定时数据如何在目标和源对象之间流动。
双向:- 数据可以从源流向目标,也可以从目标流向源。
单向:- 数据仅从源流向目标。
单向到源:- 数据仅从目标流向源。
一次性:- 数据仅在第一次从源流向目标,之后不再进行通信。
下面是一个易于记忆的表格表示。
单向到源
数据流 | ||
绑定 | 目标到源 | 源目标 |
双向 | 是 | 是 |
单向到源 | 是 | 否 |
单向 | 否 | 是 |
一次性 | 否 | 第一次是 |
你能用一个例子解释 WPF 命令吗?
当最终用户与应用程序交互时,他们会发送诸如按钮点击、右键点击、Ctrl+C、Ctrl+V 等操作。WPF 中的命令类将这些最终用户操作封装到一个类中,以便它们可以反复重用。
WPF 命令类的思想是四人帮设计模式中命令模式的实现。
要创建命令类,我们需要实现“ICommand”接口。例如,下面是一个简单的命令类,它通过调用“Increment”方法来增加计数器类。
public class IncrementCounter : System.Windows.Input.ICommand { private clsCounter obj; public IncrementCounter(clsCounter o) { obj = o; } public bool CanExecute(object parameter) { return true; } public event EventHandler CanExecuteChanged; public void Execute(object parameter) { obj.Increment(); } }
命令类需要实现上述代码所示的两个方法:-
执行什么 (Execute) – 命令类旨在封装最终用户的操作,以便我们可以重复使用它们。最终,操作会调用方法。例如,“btnmaths_click”操作会调用类的“Add”方法。我们需要在命令类中指定的第一件事是要执行哪个方法。在本例中,我们想要调用“clsCounter”类的“Increment”方法。
何时执行 (CanExecute) – 我们需要指定的第二件事是何时可以执行命令,即验证。此验证逻辑在“CanExecute”函数中指定。如果验证返回 true,则“Execute”触发,否则操作无效。
您可以在上面的代码片段中看到“CanExecute”和“Execute”的代码。
创建“Command”类后,可以使用“Command”属性将其与按钮绑定,如下面的 XAML 代码所示。“CounterObj”是一个资源对象。
<Button Command="{Binding IncrementClick, Source={StaticResource Counterobj}}"/>
因此,现在操作已封装到命令中,我们无需在后台代码中一遍又一遍地编写方法调用代码,我们只需将命令对象与必要的 WPF UI 控件绑定即可。
“UpdateSourceTrigger”如何影响绑定?
“UpdateSourceTrigger”决定了绑定在一起的 WPF 对象之间数据何时更新。换句话说,数据应该在失去焦点事件中更新,在数据更改事件中更新等等。
“UpdateSourceTrigger”可以通过四种模式定义:-
- 默认值:- 如果是文本属性,则数据在失去焦点时更新;对于普通属性,数据在属性更改事件中更新。
- PropertyChanged:- 在此设置中,数据在值更改后立即更新。
- LostFocus:- 在此设置中,数据在失去焦点事件发生后立即更新。
- Explicit:- 在此设置中,数据手动更新。换句话说,要在两个 WPF 对象之间更新数据,您需要调用以下代码。
BindingExpression binding =txt1.GetBindingExpression(TextBox.TextProperty); binding.UpdateSource();
要设置“UpdateSourceTrigger”,我们需要使用“UpdateSourceTrigger”值,该值可在绑定属性中找到,如下图所示。
解释“INotifyPropertyChanged”接口的必要性?
当我们绑定两个 WPF 对象时,目标数据会根据“UpdateSourceTrigger”事件进行更新。有关“UpdateSourceTrigger”基础知识,请参阅上一个问题。
“UpdateSourceTrigger”具有诸如失去焦点、属性更改等事件。换句话说,当目标上发生失去焦点或属性更改事件时,它会向源发出 PULL 请求以获取最新数据。
因此,WPF 源数据很可能已更改,但由于 WPF 目标“UpdateSourceTrigger”事件未触发,它没有进行拉取,并且源数据与目标不同步。这就是“INotifyPropertyChanged”接口发挥作用的地方。
下面是一个简单的“clsCounter”类,它有一个“Counter”属性,并且此属性通过“Increment”方法递增。
现在,如果我们将 WPF 标签或文本框绑定到“Counter”属性并调用“Increment”方法,则新的“Counter”值将不会传播到目标。因为调用方法不会触发任何“UpdateSourceTrigger”事件。
因此,在调用“Increment”方法后,源和目标的“Counter”值不同步。
因此,要从源创建推送事件,您需要首先实现“INotifyPropertyChanged”接口,如下图所示。现在,当有人调用“Increment”方法时,您可以通过调用“PropertyChanged”函数(如下面的代码所示)引发一个事件,表示“Counter”属性已更改。
简单来说,源向目标 WPF 对象发送通知,告知源中的数据已更改,并且它应该用新数据刷新自身。
PropertyChanged(this, new PropertyChangedEventArgs("Counter"));
下面是完整的“clsCounter”类代码,其中实现了“INotifyPropertyChanged”。
public class clsCounter : INotifyPropertyChanged { private int _Counter=0; public int Counter { get { return _Counter; } } public void Increment() { _Counter++; PropertyChanged(this, new PropertyChangedEventArgs("Counter")); } public event PropertyChangedEventHandler PropertyChanged; }
WPF 中的值转换器是什么?
绑定是 WPF 的一个重要功能,它有助于促进 WPF UI 和对象之间的数据流。但是,当数据使用这些绑定从源流向 UI 或反向流时,我们需要将数据从一种格式转换为另一种格式。例如,假设我们有一个“Person”对象,其中有一个 married 字符串属性。
假设此“married”属性与复选框绑定。因此,如果文本是“Married”,它应该返回 true,以便选项复选框看起来已选中。如果文本是“Unmarried”,它应该返回 false,以便选项复选框看起来未选中。
简单来说,我们需要进行数据转换。这可以通过使用“Value Converters”来实现。为了实现值转换器,我们需要继承“IValueConverted”接口并实现“Convert”和“ConvertBack”两个方法。
public class MaritalConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string married = (string)value; if (married == "Married") { return true; } else { return false; } } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { bool married = (bool)value; if (married) { return "Married"; } else { return "UnMarried"; } } }
您可以在“Convert”函数中看到我们编写了将“Married”转换为 true,将“Unmarried”转换为 false 的逻辑。在“ConvertBack”函数中,我们实现了相反的逻辑。
解释 WPF 中的多重绑定和多值转换器?
“MultiBinding”帮助您将多个源绑定到目标,而多转换器则充当桥梁,如果源和目标具有不同的数据格式或需要某些转换。
例如,假设您有两个文本框,分别包含“FirstName”和“LastName”。您希望一旦用户在这两个文本框中输入,另一个文本框就会更新为“FirstNameLastName”(如下图所示)。
反之,如果我们在第三个文本框中输入“FirstNameLastName”,它应该分别在另外两个文本框中显示“FirstName”和“LastName”。
因此,第一件事是创建一个多值转换器类,它将“FirstName”和“LastName”合并到源中,并将“FirstNameLastName”拆分回目标。为此,我们需要实现“IMultiValueConverter”并实现“Convert”和“ConvertBack”方法。
“Convert”有助于将数据从“目标”转换为“源”,“ConvertBack”有助于将数据从“源”转换为“目标”。
public class NameMultiConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // Conversion logic from Target to Source } } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { // Conversion logic from Source to Target. } }
下面是“Convert”(目标到源)的实现,我们以数组形式获取“文本框”值,并连接数组值并以单个字符串的形式返回。此单个字符串将显示在第三个文本框中。
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string x = ""; foreach (object y in values) { x = x + " " + y.ToString(); } return x; }
“ConvertBack”有助于实现从“源”到“目标”的转换逻辑。因此,当有人在第三个文本框中输入“Shiv Koirala”时,我们希望将“Shiv”拆分为一个字符串,“Koirala”拆分为另一个字符串。
因此,您可以在下面的代码中看到我们使用了“Split”函数来创建一个字符串数组。因此,第一个数组索引 (array[0]) 将进入第一个文本框,第二个数组索引 (array[1]) 将进入第二个文本框。
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { string str = (string)value; string[] val = str.Split(' '); return val; }
现在我们完成了转换器,下一步是应用多重绑定。下面是 XAML 代码,其中我们有三个文本框“txtFirstName”、“txtLastName”和“txtFirstAndLast”。
您可以看到“txtFirstAndLast”文本框的“Text”是如何使用多重绑定元素进行绑定的,它绑定到“txtFirstName”和“txtLastName”文本框。因此,现在如果您更改多个目标,单个源会更新;如果您更新源,多个目标会更新。
<TextBox x:Name="txtFirstName" HorizontalAlignment="Left" Height="26" Margin="42,67,0,0" TextWrapping="Wrap" Text=""
VerticalAlignment="Top" Width="152"/>
<TextBox x:Name="txtLastName" HorizontalAlignment="Left" Height="26" Margin="41,135,0,0" TextWrapping="Wrap" Text=""
VerticalAlignment="Top" Width="153"/>
解释 WPF 相对绑定/相对资源?
当我们定义绑定时,至少需要两个元素:目标和源。但很多时候,我们更希望相对于当前元素(即相对地)定义绑定,而不是在两个元素之间定义绑定。
例如,假设我们有一个 WPF 边框,我们希望边框的高度和宽度相同。因此,在这种情况下,目标和源是相同的,即 WPF 边框本身。因此,我们可以使用“RelativeSource”定义绑定,如下面的代码所示。您可以看到它使用“Self”绑定模式将元素绑定到自身。
<Border BorderBrush="Black" BorderThickness="1" Height="139" Width="{Binding Height, RelativeSource={RelativeSource Self}}"/>
使用相对源进行绑定的不同方式有哪些?
在 WPF 中有四种相对绑定方式:-
- Self
- Ancestor (祖先)
- PreviousData (前一个数据)
- Templated Parent (模板父级)
你能解释 WPF 中的自相对源绑定吗?
这种相对绑定有助于将一个元素的属性绑定到同一元素的另一个属性。例如,在下面的 XAML 中,边框宽度绑定到同一边框元素的高度。
<Border BorderBrush="Black" BorderThickness="1" Height="139" Width="{Binding Height, RelativeSource={RelativeSource Self}}"/>
解释 WPF 中的祖先相对源绑定?
这种相对绑定有助于将属性绑定到父元素的属性。例如,在下面的 XAML 代码中,我们有一个文本框,它有两个边框作为父级。一个边框的边框颜色是深绿色,另一个边框的边框颜色是深红色。
深绿色边框是父元素,其次是深红色边框,文本框是层次结构末尾的子元素。
<Border BorderBrush="DarkGreen">
<Border BorderBrush="DarkRed”>
下面是 WPF 应用程序运行时看起来的样子。
现在我们希望文本框的背景颜色绑定到其中一个父边框的颜色。为了实现这一点,我们可以使用祖先相对绑定。
在编写绑定代码之前,我们需要了解以下 Ancestor 类型绑定中的一些重要属性。
属性 | 描述 |
AncestorType | 它是什么类型的父元素?是边框元素、网格元素等等。 |
AncestorLevel | 一个元素可以有多个父元素。例如,在上面的 XAML 中,我们有两个父元素,一个红色,一个绿色。因此,此属性指定我们要引用的父元素的级别。下图描绘了这些级别。红色边框是级别 1,绿色边框是级别 2。 因此,最接近的元素成为第一级,依此类推。 |
数据绑定。 | 这指定了我们要绑定到哪个属性。对于当前示例,我们想要绑定到边框的画刷颜色。 |
因此,祖先级别为 1(即红色)的相对绑定代码如下所示。如果您对任何属性感到困惑,请参阅上表以获取更多信息。
<TextBox Background="{Binding BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type Border}}}"/>
因此,现在包含父边框元素的完整 XAML 如下面的代码所示。
<Border BorderBrush="DarkGreen"><!-- Level 2 ->
现在,如果您运行上面的 XAML 代码,文本框将绑定到第一个边框的背景颜色。如果将祖先级别更改为 2,文本框的背景颜色将变为绿色。
PreviousData
<ItemsControlItemsSource="{Binding}" Margin="10">
<ItemsControl.ItemTemplate>
publicclassItem : INotifyPropertyChanged
{
privatedouble _value;
publicdouble Value
{
get { return _value; }
set { _value = value; OnPropertyChanged("Value"); }
}
#regionINotifyPropertyChanged Members
publiceventPropertyChangedEventHandlerPropertyChanged;
#endregion
protectedvoidOnPropertyChanged(stringPropertyName)
{
if (null != PropertyChanged)
{
PropertyChanged(this,
newPropertyChangedEventArgs(PropertyName));
}
}
}
publicclassItems : ObservableCollection-
{
public Items()
{
Add(newItem { Value = 80.23 });
Add(newItem { Value = 126.17 });
Add(newItem { Value = 130.21 });
Add(newItem { Value = 115.28 });
Add(newItem { Value = 131.21 });
Add(newItem { Value = 135.22 });
Add(newItem { Value = 120.27 });
Add(newItem { Value = 110.25 });
Add(newItem { Value = 90.20 });
}
}
解释 WPF 中可视化树和逻辑树的区别?
WPF UI 以 XAML 形式表示,这是一种 XML 格式。在 XML 中,元素以层次结构方式排列。例如,如果您查看下面的 XAML(为简化已缩小),我们有一个 Window 元素,Window 元素有一个 Grid 控件,Grid 控件里面有一个 Button。
<Window>
<Grid>
<Button..>
因此,如果您逻辑上可视化上述 XAML,您可以认为按钮控件是网格的子元素,而网格是窗口的子元素。这种元素之间的关系(从 XAML 来看是逻辑关系)被称为“逻辑树”。
但是现在,为了将这个逻辑树显示在您的屏幕上,您需要很多可视化元素。例如边框、文本等。因此,当您将这些可视化元素添加到逻辑树时,该完整结构被称为“可视化树”。
简单来说,WPF 中只有一个树,但根据您如何查看它,会产生这两个树。如果您使用 WPF 可视化工具,上述 XAML 树看起来如下图所示,它实际上是一个完整的可视化树。
简单来说,您在 XAML 中看到的任何东西都是逻辑树,为了显示它,它使用了视觉树。下面是一个详细的图,显示了上述 XAML 的逻辑树和视觉树。没有阴影的是逻辑树,有阴影的是视觉树。
为什么我们需要在 WPF 中拥有可视化树和逻辑树的概念?
当您使用 WPF 路由事件时,视觉树和逻辑树非常重要。
解释 WPF 中的路由事件?
路由事件是指在视觉树层次结构中向上或向下传播的事件。WPF 事件可分为 3 种类型:-
直接事件:- 在这种情况下,事件在源处引发并在源处处理,例如“MouseEnter”事件。
冒泡事件:- 它们在视觉树层次结构中向上传播。例如,“MouseDown”是一个冒泡事件。
隧道事件:- 这些事件在视觉树层次结构中向下传播。“PreviewKeyDown”是一个隧道事件。
WPF 中的样式是什么?
WPF 样式有助于从中心位置定义外观和感觉(颜色、字体、对齐方式等),从而方便维护。有关 WPF 样式的更多详细信息,请查看此链接,其中还包含简单的 WPF 示例
什么是样式触发器?
很多时候,我们希望样式属性在特定条件下执行。触发器可帮助您定义设置样式值的条件。
例如,在下面的 XAML 代码中,我们为按钮定义了样式触发器,如果按钮获得焦点,则将其背景颜色设置为“红色”,否则将其背景颜色设置为“水蓝色”。
<Style x:Key="myStyle" TargetType="Button">
<Style.Triggers>
</Style.Triggers>
</Style>
什么是 MVVM?
MVVM 是一种架构模式,我们将项目划分为三个逻辑层,每个层都有自己的职责。
以下是三个逻辑层及其说明:-
- 视图:- 此层负责处理从最终用户获取输入、控件定位、外观、设计、视觉效果、颜色等。
- 模型:- 此层代表您的中间层对象,如客户、供应商等。它处理业务逻辑和与数据访问层的交互。
- 视图模型:- 视图模型,顾名思义,视图加模型代表您的用户界面。您也可以将此类视为后台代码。此类是模型和视图之间的桥梁。它处理连接逻辑、数据转换逻辑以及模型和视图之间的动作映射。例如,它将具有以下类型的逻辑,如下所示:-
在视图和模型之间复制和传播数据。当有人在 UI 中输入数据或模型更新时,此层将确保数据在这些实体之间传播。
处理从视图到模型以及反向的数据转换。例如,您有一个模型,其中有一个性别属性,数据为男性“M”,女性“F”。但在视图或 UI 上,您希望将其显示为带有 true 和 false 的复选框。此转换逻辑是在视图模型类中编写的。
视图模型还将 UI 操作映射到方法。例如,您有一个“btn_Add”单击事件,当任何人单击此按钮时,您希望调用客户类中的“Customer.Add()”方法。此连接代码再次是视图模型的一部分。
MVVM 的好处是什么?
以下是 MVVM 模式的优点:-
职责分离:- 由于项目被划分为多个层,每个层都处理自己的职责。这导致更好的维护,因为当我们更改一个层时,其他层不会受到影响。
提高了 UI 可重用性:- MVVM 的全部意义在于移除后台代码,即 XAML.CS 代码。后台代码的问题在于它与 UI 技术绑定,例如 ASPX.CS 代码与 ASP 页面类绑定,XAML.CS 文件与 WPF UI 技术绑定等等。因此,我们不能将 ASPX.CS 后台代码与 WPF XAML UI 一起使用。
通过将后台代码移动到视图模型类,我们现在可以将其与任何 UI 技术一起使用。
自动化 UI 单元测试:- 视图模型类代表您的 UI。类的属性代表 UI 文本框、组合框,类的方法代表操作。现在,由于 UI 由视图模型类表示,我们可以通过创建视图模型类的对象并进行必要的断言来使用单元测试进行自动化 UI 测试。
命令和绑定在 MVVM 模式中有什么重要性?
MVVM 是最常用的架构,因为它提供了 WPF 的命令和绑定功能。没有命令和绑定,WPF MVVM 就是不完整的。
命令和绑定帮助您连接视图(WPF UI)和视图模型类,而无需编写大量后台代码。绑定将 UI 输入元素(文本框、组合框等)与视图模型类属性连接起来,而 UI 操作(如按钮单击、右键单击)通过命令连接到类的方法。
Note :- Please refer previous questions to understand command and bindings.
MVVM 和三层架构的区别是什么?
MVVM 比三层架构多一层。在三层架构中,我们有 UI(视图)、业务逻辑(模型)和数据访问层(DAL)。在 MVVM 中,我们在视图和模型之间多了一层,即视图模型类。
三层架构补充了 MVVM 架构。
解释委托命令?
首先简短回答:- “委托命令使 MVVM 命令类独立于视图模型”。现在让我们详细理解。
在 MVVM 架构中,视图与视图模型对话,视图模型与模型对话。当操作从视图发送时,它们被发送到 WPF 命令以处理事件。WPF 命令在内部调用视图模型的方法。
换句话说,命令需要视图模型类的引用。
如果您看到典型的 WPF MVVM 命令,它如下图所示。您可以看到“CustomerViewModel”类在“btnCommand”类中被引用。如果您闭上眼睛思考,命令内部对“CustomerViewModel”类的这种引用是一个问题。这将导致命令类和视图模型之间紧密耦合。
如果您将命令可视化,它不过是单击、双击、鼠标左键单击、拖放等。它是用户创建的 ACTION。现在,如果我们能将此命令与任何视图模型关联起来,那不是很好吗?因此,例如单击事件可以与“CustomerViewModel”或“SupplierViewModel”连接。
这可以通过使用委托命令来实现。
public class btnCommand : ICommand
{
Private CustomerViewModel Viewobj = new CustomerViewModel();
public btnCommand(CustomerViewModel obj)
{
Viewobj = obj;
}
public bool CanExecute(object parameter) // When he should execute
{
return Viewobj.IsValid();
}
public void Execute(object parameter) // What to execute
{
ViewObj.Add();
}
}
为了将视图模型类与命令解耦,我们可以使用委托,即“Action”和“Func”。如果您查看命令类,我们只需要两件事:“WhattoExecute”和“WhentoExecute”。那么,如何将这些方法作为泛型委托传递呢?您可以看到“btnCommand”的构造函数接受两个委托,一个是要执行什么,另一个是何时执行。
您可以在下面的代码中看到,“btnCommand”类没有视图模型类的引用,但有委托的引用,这些委托只是函数/方法的抽象指针。因此,此命令类现在可以与任何视图模型类关联。这种方法被称为“委托命令”。
public class btnCommand : ICommand // Step 1 :- Create command
{
private Action WhattoExecute;
private Func<bool> WhentoExecute;
public btnCommand(Action What , Func<bool> When)
{
WhattoExecute = What;
WhentoExecute = When;
}
public bool CanExecute(object parameter) // When he should execute
{
return WhentoExecute();
}
public void Execute(object parameter) // What to execute
{
WhattoExecute();
}
}
什么是 PRISM?
PRISM 是一个用于在 WPF 和 Silverlight 中开发复合应用程序的框架。复合应用程序是使用组合构建的。换句话说,我们不是从头开始构建应用程序,而是获取预构建的组件,将它们组装在一起并创建应用程序。
请看下面简单的 WPF UI 示例。您可以看到它有很多部分。现在,我们不是将整个 UI 构建为一个大型单元,而是可以将所有这些部分开发为独立的单元。稍后,通过使用 PRISM,我们可以通过获取所有这些独立的单元来组合 WPF UI。
PRISM 的好处是什么?
模块化开发:- 由于我们将组件开发为独立的单元,因此我们可以将这些单元分配给不同的开发人员并进行模块化并行开发。通过并行开发,项目将更快交付。
高重用性:- 由于组件是以独立单元开发,我们可以使用 PRISM 轻松地插入它们并创建组合 UI。
各个单元如何组合成一个单元?
PRISM 为此使用依赖注入。请参阅设计模式部分以阅读有关 DI(依赖注入)的内容。我们可以通过两种方式进行 DI:使用 Unity 应用程序块或 MEF(托管可扩展性框架)。
PRISM 实现 MVVM 吗?
PRISM 的主要重点是模块化开发,而不是 MVVM。但它确实有现成的类,例如委托命令,可以帮助我们减少 MVVM 代码。但请注意,PRISM 的主要目标不是 MVVM。
PRISM 是 WPF 的一部分吗?
不,PRISM 是一个单独的安装程序。
什么是 Expression Blend?
Expression Blend 是一款用于 WPF 和 SilverLight 应用程序的设计工具。
我在 CodeProject 上的其他面试题文章
MVC 面试题 - https://codeproject.org.cn/Articles/556995/MVC-interview-questions-with-answers
Entity Framework 面试题 - https://codeproject.org.cn/Articles/676309/ADO-NET-Entity-Framework-Interview-Questions
HTML 5 面试题 - https://codeproject.org.cn/Articles/702051/important-HTML-Interview-questions-with-answe