我使用XAML和PowerShell创建了一个简单的WPF应用程序,其中包含一个TabControl,我希望在其子TabItem中显示多种数据。根据提供的数据类型,我希望TabControl的子TabItems使用不同的DataTemplate。
我了解在我的情况下,最好的(唯一的)方法是在C#中创建一个自定义DataTemplateSelector类来处理模板选择。
我尝试这样做,但是在使用自定义类时遇到困难。这是我得到的错误:
print (df)
col1 col2 col3 col4 col5 average
0 abc 123 1 4 9 4.666667
1 def None 2 7 None 4.500000
2 ghi 456 5 None 3 4.000000
3 jkl 789 None 8 8 8.000000
我怀疑我没有正确加载所需的程序集或名称空间,因此无法访问我的自定义名称空间和自定义类。我以前从未使用过C#,因此,我非常感谢提供的任何手持工具。
一旦我解决了这个问题,我就知道我的C#自定义类的内部逻辑将无法正常工作,但这是一个单独的问题。 C#代码似乎有效,因为我可以独立运行它并实例化自定义类。
如果我删除所有与DataTemplateSelector相关的位并将以下内容添加到TabControl,则XAML和代码也可以正常工作:
ContentTemplate="{StaticResource UserDataTemplate}"
以下是代码(包括C#,XAML,PowerShell):
Exception calling "Load" with "1" argument(s): "Cannot create unknown type
'{clr-namespace:myNamespace}myDataTemplateSelector'."
At line:101 char:1
+ $Window = [Windows.Markup.XamlReader]::Load($Reader)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : XamlParseException
我还探索了将XAML数据模板存储为PowerShell变量,并在添加子级之前将TabControl的ContentTemplate属性设置为适当的DataTemplate。在阅读了WPF的模板文档之后,这是不成功的,也许是不可能的。
我愿意接受其他方法。感谢您的宝贵时间。
答案 0 :(得分:2)
正如史莱姆食谱所建议的那样,首先在Visual Studio中创建控件库的痛苦要小得多。
我在Visual Studio中创建了一个新的“类库(.NET Framework)”项目,将现有的语法有效的C#代码粘贴到解决方案中,添加了对适当程序集的引用,并构建了该项目。
我将生成的myDataTemplateSelector.dll文件复制到PowerShell脚本文件所在的目录。
我加载了一个新的PowerShell控制台(重新使用控制台未正确加载程序集),并运行了以下命令来测试DLL:
Add-Type -Path .\myDataTemplateSelector.dll
[myNamespace.myDataTemplateSelector]::New()
这成功实例化了我的自定义类。
最后,我更新了XAML:
xmlns:local="clr-namespace:myNamespace;assembly=myDataTemplateSelectorLibrary"
WPF应用程序现在开始运行!
我将不胜感激,因为其他任何答案都可以解释如何完成同一件事而无需在Visual Studio中编译C#代码,因为我宁愿不依赖于人类中不可读的文件(即DLL文件)。这个项目。
编辑-完整回答:
切片配方建议以编程方式找到程序集名称,而不是依赖于我假定的名称(基于C#代码)使我走了正确的道路。再次感谢。
在PowerShell中运行C#代码时,通常使用Add-Type,它将代码仅加载到内存中。
如果您指定源代码,则Add-Type会编译指定的源代码并生成一个包含新.NET Framework类型的内存中程序集。
为了访问所添加代码的元数据,必须使用Add-Type的-Passthru参数:
-PassThru
返回一个System.Runtime对象,该对象表示添加的类型。默认情况下,[Add-Type]不生成任何输出。
然后我存储了修改后的Add-Type命令的输出:
$Type = Add-Type -TypeDefinition $cSharpSource -ReferencedAssemblies $Assemblies -PassThru
然后可以访问程序集的全名:
> $Type.Assembly.Fullname
m0m5m4la, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
第一个字符串'm0m5m4la'是所需的程序集名称,当添加类型时,它似乎是随机生成的,并用作对内存中程序集的引用。
最后,可以在脚本运行并将其插入XAML时对其进行访问:
...
$Type = Add-Type -TypeDefinition $cSharpSource -ReferencedAssemblies $Assemblies -PassThru
$AssemblyName = $Type.Assembly.Fullname.Split(",",2)[0]
Add-Type -AssemblyName PresentationFramework
[xml]$XAML = @"
<Window x:Name="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="650" Width="300" FontSize="11"
xmlns:local="clr-namespace:myNamespace;assembly=$($AssemblyName)">
...
我不确定这有多糟糕,但是它可以工作并且允许所有代码保留为纯文本格式,并且不需要软件工具(除了文本编辑器)即可继续开发。
我可能搜索的不够好,但是在网上找不到这样的例子。希望这对外面的人有帮助!
答案 1 :(得分:1)
您需要指定程序集和名称空间。 local =“ clr-namespace:myNamespace”仅指定名称空间。我不确定您在PS环境中如何工作。
答案 2 :(得分:0)
要在当前脚本中引用类,可以做到这一点。
xmlns:local="clr-namespace:$([YourClass].Namespace);assembly=$([YourClass].Assembly.FullName)"
然后您可以创建一个静态资源并瞧瞧:)
<Window.Resources>
<local:YourClass x:Key="_yclass" />
</Window.Resources>