【问题标题】:WPF/XAML: How to reference class that is not defined within any namespaceWPF/XAML:如何引用未在任何命名空间中定义的类
【发布时间】:2025-12-29 12:00:07
【问题描述】:

我正在执行一个尝试定义和打开 WPF 窗口的 roslyn 脚本。

除此之外,我的脚本

  1. 定义附加行为
  2. 定义了一个 XAML 字符串,基于它我创建了一个 WPF 窗口。在此 XAML 代码中,我想使用脚本中定义的 TextBoxCursorPositionBehavior。

我的脚本 (.csx) 文件看起来类似于

public class TextBoxCursorPositionBehavior : DependencyObject
{
    // see http://*.com/questions/28233878/how-to-bind-to-caretindex-aka-curser-position-of-an-textbox
}

public class MyGui
{
    public void Show()
    {
      string xaml = File.ReadAllText(@"GUI_Definition.xaml");

      using (var sr = ToStream(xaml))
      {
        System.Windows.Markup.ParserContext parserContext = new System.Windows.Markup.ParserContext();
        parserContext.XmlnsDictionary.Add( "", "http://schemas.microsoft.com/winfx/2006/xaml/presentation" );
        parserContext.XmlnsDictionary.Add( "x", "http://schemas.microsoft.com/winfx/2006/xaml" );
        parserContext.XmlnsDictionary.Add("i","clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity");

        // ?? How  can i define this properly?
        parserContext.XmlnsDictionary.Add("behaviors", "clr-namespace:;assembly=" + typeof(TextBoxCursorPositionBehavior).Assembly.FullName);

        var window = (System.Windows.Window)XamlReader.Load(sr, parserContext);
        window.ShowDialog();
      }
    }
}

并假设 GUI_Definition.xaml 看起来像

<Window x:Class="System.Windows.Window" Height="300" Width="300" >
<Grid>
  <!-- how can i attach my behavior here properly? -->
  <TextBox behaviors:TextBoxCursorPositionBehavior.TrackCaretIndex="True"/>
</Grid>
</Window>

但问题是,如何在 XAML 中正确引用 TextBoxCursorPositionBehavior?

Roslyn 不允许在脚本文件中使用命名空间,因此 TextBoxCursorPositionBehavior 必须在命名空间之外定义(即我想它会落入全局命名空间)。

但是,我如何在 XAML 中引用它?我尝试使用“clr-namespace:;assembly=" + typeof(TextBoxCursorPositionBehavior).ToString() 定义命名空间引用,但这不起作用。 简单的“clr-namespace:”(即没有程序集引用)也不起作用。

有没有办法从 XAML 定义中引用 TextBoxCursorPositionBehavior?

【问题讨论】:

    标签: c# wpf xaml roslyn


    【解决方案1】:

    在您的代码而不是您使用的程序集中:

    typeof(TextBoxCursorPositionBehavior).ToString()
    

    这不是程序集名称。将其更改为:

    parserContext.XmlnsDictionary.Add("behaviors", "clr-namespace:;assembly=" + Assembly.GetExecutingAssembly().FullName);
    

    它应该可以正常工作(至少对我有用,但我不使用 Roslyn 脚本进行测试,而只是使用常规 WPF 应用程序)。

    【讨论】:

    • 我的错,编辑了我的 * 脚本以减小大小 - 实际上在我的实际脚本中有一个正确的程序集引用,它产生了与您的代码相同的结果/字符串。有趣的是,这在常规项目中对您有用;想知道这是否确实与罗斯林有关。错误是“无法设置未知成员 '{clr-namespace:,assembly=ℛ*a195d238-7cf0-48ab-999f-2a6e28db1c13#125-0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null}TextBoxCursorPositionBehavior.TrackCaretIndex' "
    • 啊,我想我知道出了什么问题;将在下面发布更多空间/可见性
    【解决方案2】:

    我想我知道发生了什么... Roslyn 为脚本创建了一个自定义提交类型,并且似乎所有内容(包括 TextBoxCursorPointerBehavior 的定义)都是此提交类型的子类。即,

            var inst = new TextBoxCursorPositionBehavior();
            string typeName = inst.GetType().FullName;
    

    typeName 不会是“TextBoxCursorPointerBehavior”,而是“Submission#0+TextBoxCursorPositionBehavior”。

    同时,我不能从 XAML 中引用它(例如通过行为:Submission#0+TextBoxCursorPositionBehavior.TrackCaretIndex="True"),因为它不会正确解析名称(# 是一个无效的标记)。

    理论上,可以将 Roslyn 的提交类型重命名为实际上可通过 XAML 引用的内容 - 但就我而言,我不能这样做。

    不幸的是,目前我没有看到任何解决我的问题的方法,除了可能将此代码外包给单独的预编译 DLL(但这也不是编写脚本的重点)

    【讨论】:

    • 仅使用 CSharpScript.Evaluate 执行脚本的准确程度如何?
    • 我正在用 SourceCodeKind = Script 编译一个内存程序集,并自己确定提交类型/调用工厂方法。不过,这应该与 CSharpScript.Create() 和 .RunAsync() 相对较好;特别是程序集的创建方式、提交类的设置方式等都是 Roslyn 的默认设置,我不干预。