且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

尝试在 PowerShell 中实现 IValueConverter 时出错 - XAML GUI 脚本

更新时间:2022-12-05 14:32:29

我注册了 *** 只是为了参与这个问题.

I signed up for *** just so I could participate in this question.

在我在这里遇到这个问题之前,我搜索了 HOURS 来解决这个问题,然后我的希望破灭了,看到它已经在这里坐了将近一年没有答案.

I searched for HOURS for a solution to this before I ran across this question here, and then my hopes were dashed to see it's been sitting out here almost a year with no answer.

我之前发现了这个相关问题,它提供了我们试图用这个问题实现的基本解决方案,但没有提供任何有关使其实际工作的细节.如何从 powershell 使用 IValueConverter?

I had found this related question earlier, and it gives the basic solution we're trying to implement with this question, but doesn't give any details on making it actually work. How to use IValueConverter from powershell?

幸运的是,经过几个小时,并拼凑了很多其他信息,我终于解决了!

Luckily, after several more hours, and piecing together a lot of other info, I finally solved it!

它有 3 个部分.

  1. 通过 C# 代码添加的转换器类型不是表单的同一命名空间的一部分,即使您在 C# 类代码中指定了表单的命名空间.所以需要一个额外的 xmlns: 行来在表单中包含转换器类型的命名空间.然后在表单资源中定义转换器时,您引用该名称空间而不是表单自己的名称空间(通常是本地",但我看到您使用了cnv"的示例).此外,出于以下原因,您希望 C# 代码中的命名空间与表单自己的命名空间不同.(我不确定,但系统可能会因为 2 个不同的命名空间实际上在物理上分开而感到困惑.)
  2. 但是,即使添加了 xmlns: 行以包含转换器的命名空间,表单仍然无法找到它.这是因为,我发现,添加的转换器类型也被添加到不同的程序集中.显然,当使用Add-Type -TypeDefinition"添加自定义类型时,PowerShell 会创建自己的内存程序集并将类型添加到其中.因此,在添加的 xmlns: 行中包含转换器的命名空间,我们还必须为自定义转换器类型指定程序集.
  3. 但是,但是……更糟糕的是,这个编造"的程序集有一个随机生成的名称,并且每次运行脚本时程序集名称都不同.(我在任何地方都找不到这个事实的记录.我完全是偶然发现的.)那么,如果您不知道程序集名称,如何包含程序集名称?基本上做你所做的,在变量中创建新转换器对象的实例,然后检查该新对象变量的属性以确定程序集名称.然后使用字符串替换用程序集名称更新您的 XAML 字符串.

SO,请参阅我发布的更新代码,其中包含以下更改.正如原始海报所示,此示例并未显示转换器的运行情况,但脚本至少会运行并显示表单而不会出错,表明表单本身接受了 TextBox 中的转换器定义和用法.

SO, see the updated code I posted which has the following changes. As the original poster indicated, this example doesn't show the converter in action, but the script will at least run and display the form without error, indicating the the form itself accepted the converter definition and usage in the TextBox.

  • 将 C# 代码中的命名空间更改为 MyConverter,使其有所不同来自表单的 MyProject 命名空间.
  • 在创建转换器对象的 $c 实例的行中,我将命名空间更改为 MyConverter 而不是 MyProject,以匹配上面的新命名空间.
  • 添加了 $AssemblyName 变量以提取随机程序集名称.(我还注释掉了对 Convert 和 ConvertBack 的调用.)
  • 将 XAML 代码的 Here-String 更改为字符串变量 $inputXML,以便我们可以对其使用 Replace.稍后将转换为 xml 文档.
  • xlmns:Converter 行已添加以包含 MyConverter 命名空间.注意;assembly=myassembly"部分.myassembly"名称只是字符串 Replace 的占位符,以便以后轻松找到.
  • 在转换器 Window.Resources 的声明中,将cnv:"更改为Converter:"以匹配转换器类型的命名空间声明.
  • 添加了另一个文本框以显示包含转换器并且表单构建接受此.
  • 添加了 [xml]$XAML = $inputXML.... 行以转换为 xml 并替换为实际程序集名称.

代码

$src = @'
    using System;
    using System.Windows;
    using System.Windows.Data;
    using System.Globalization;

    namespace MyConverter
    {

        public class DemoConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value == null)
                {
                    return "kuku";
                }
                else
                {            
                    return "bobo";
                }
            }
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {   
                return value;
            }
        }
    }
'@

Add-Type -AssemblyName PresentationFramework    
Add-Type -TypeDefinition $src -ReferencedAssemblies PresentationFramework

#Checking that the new type works and convert is done...
$c = new-object MyConverter.DemoConverter
$AssemblyName = $c.gettype().Assembly.FullName.Split(',')[0]
#$c.Convert("gg", $null, $null, $null)
#$c.Convert(55, $null, $null, $null)

#Now declaring and loading the xaml
$inputXML = @'

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Converter="clr-namespace:MyConverter;assembly=myassembly"
xmlns:cnv="clr-namespace:MyProject" >
    <Window.Resources>
        <Converter:DemoConverter x:Key="TestConverter" />
    </Window.Resources>
    <Grid>     
        <TextBox x:Name="txtTestValue" Text="I'm here to show that xaml loading works!" />
        <TextBox x:Name="txtTestValue2" Text="{Binding Path=Whatever, Converter={StaticResource TestConverter}}" />
   </Grid>
</Window>
'@

[xml]$XAML = $inputXML -replace 'myassembly', $AssemblyName

$reader=(New-Object System.Xml.XmlNodeReader $xaml) 

$Window=[Windows.Markup.XamlReader]::Load( $reader )

$Window.ShowDialog() | out-null