XAML - 命名空间

发布时间 2023-07-30 01:01:52作者: euv

演示如何使用第三方控件库 MyControls.dll

  1. 首先肯定要先添加第三方库的引用或其Nuget包。
  2. 在CS文件或XAML文件中使用库中的类都要先导入命名空间。

CS文件中使用库中类

// 方式1
using MyNamespace.Controls.Panels;
using MyNamespace.Controls.ContentControls;
MyPanel panel = new MyPanel();
MyButton button = new MyButton();

// 方式2
var panel = new MyNamespace.Controls.Panels.MyPanel();
var button = new MyNamespace.Controls.ContentControls.MyButton();

xaml文件中使用库中类

// 导入命名空间
xmlns:euv1="clr-namespace:MyNamespace.Controls.Panels;assembly=MyControls"
xmlns:euv2="clr-namespace:MyNamespace.Controls.ContentControls;assembly=MyControls"

// 使用类
<euv1:MyPanel/>
<euv2:MyButton/>

在XAML中使用类也需要先导入命名空间。
clr-namespace:后是类所在命名空间,assembly=后是类所在程序集名称,xmlns是xml namespance缩写,后面是对命名空间的简称(如euv1和euv2),简称可以是任意简短的字符串但要求不能和其他简称重复。

演示如何在XAML中使用基础类型

xmlns:sys="clr-namespace:System;assembly=mscorlib"

 <Application.Resources>
    <sys:Int32 x:Key="intMeaning">42</sys:Int32>
  </Application.Resources>

显而易见,基础类型的使用也遵守 xmlns:命名空间简称="clr-namespace:命名空间;assembly=程序集名称"

解析XAML内置的微软命名空间

<Window x:Class="Getter在UI线程执行吗.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Getter在UI线程执行吗"
        xmlns:sys="clr-namespace:Microsoft;assembly=System"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <ToggleButton Content="Click Me"/>
    </StackPanel>
</Window>
xmlns:local为什么没有指定assembly

如果在XAML文件中使用自身所在程序集的类,也需要先导入命名空间,但是可以省略assembly。缺少assembly的xmlns会在本程序集中寻找命名空间下的类。

StackPanel和ToggleButton实例化为什么不用加xmlns简称?

上面的代码片段有4个xmlns,注意到xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"是没有简称的,而其他3个都有简称x,local,sys。XAML语法允许XAML文件中最多有一个无简称的xmlns,使用此xmlns内的控件类不需要加简称。这相当于一个语法糖,因为在一个XAML中使用最多的类就是微软内置的控件,如Button,TextBlock,ListBox,StackPanel,ToggleButton,etc.,如果使用这些控件类时都加上简称显得比较臃肿麻烦。不加简称的类默认使用的就是缺少简称的xmlns。我们可以把微软内置的缺前缀的xmlns改成不缺简称的:

<microsoft:Window x:Class="Getter在UI线程执行吗.MainWindow"
           xmlns:microsoft="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 Title="MainWindow" Height="450" Width="800">
    <microsoft:StackPanel>
        <microsoft:ToggleButton Content="Click Me"/>
    </microsoft:StackPanel>
</microsoft:Window>

推荐使用最频繁的xmlns不加简称,那么在逻辑树和可视化树使用其所包含的类时,不需要写简称,比较简洁!

网址作为xmlns很怪异

仔细观察xmlns,可以看到有些xmlns需要指定clr-namespace和assembly,但是有些xmlns只需要指定一个网址。这是为什么呢?

xmlns:sys="clr-namespace:Microsoft;assembly=System"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

如果一个控件库提供的类很多,那么命名空间大概率也会很多,使用该库,要写很多xmlns来导入众多的命名空间,这样会显得杂乱。
所以提供第三方库时,可以为部分命名空间或全部的命名空间起个统一的别名,别名可以是任意字符串,建议是项目的github网址或相关网站!那么在使用库时,只需要导入1个网址形式的命名空间即相当于导入库中多个命名空间。

为第三控件库制作网址形式命名空间的方法如下

第三方库在AssemblyInfo.cs中添加如下片段

using System.Windows.Markup;
[assembly:XmlnsDefinition("https://gihub.com/euv7/MyControls", "MyNamespace.Controls.Panels")]
[assembly: XmlnsDefinition("https://gihub.com/euv7/MyControls", "MyNamespace.Controls.ContentControls")]
[assembly: XmlnsPrefix("https://gihub.com/euv7/MyControls", "euv")]

使用第三方库的客户端

xmlns:euv="https://gihub.com/euv7/MyControls"

 <euv:MyPanel/>
 <euv:MyButton/>

其中
xmlns:euv="https://gihub.com/euv7/MyControls"

相当于

xmlns:euv1="MyNamespace.Controls.Panels;assembly=MyControls"

xmlns:euv2="MyNamespace.Controls.ContentControls;assembly=MyControls"

assembly: XmlnsPrefix是推荐的xmlns简称,当然在导入网址命名空间时不使用推荐的简称也是允许的,如
不写 xmlns:euv="https://gihub.com/euv7/MyControls",而是写 xmlns:bruce="https://gihub.com/euv7/MyControls"

建议第三方库提供简称,那么客户端在导入命名空间时,输入xmlns:简称=后IDE便会有智能提示。
建议网址中包含dll名称,那么客户端在输入xmlns:简称=后,不明确输入哪个网址时输入dll名称部分字符串会有智能提示。

同一个网址命名空间实际上包含多个命名空间
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    <StackPanel>
        <ToggleButton Content="Click Me"/>
    </StackPanel>

StackPanel的命名空间是System.Windows.Controls
ToggleButton的命名空间是System.Windows.Controls.Primitives


如果在开发第三方库时,不想让客户端使用库的时候还需要导入命名空间,那么可以直接在库的AssemblyInfo.cs文件中指定的网址xmlns就是http://schemas.microsoft.com/winfx/2006/xaml/presentation,因为每个XAML文件都包含此微软提供的默认xmlns。但是缺点是容易导致控件类命名空间重叠冲突编译时报错说有歧义。