首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >序列化WPF DataTemplates和{Binding表达式}(来自PowerShell?)

序列化WPF DataTemplates和{Binding表达式}(来自PowerShell?)
EN

Stack Overflow用户
提问于 2010-03-21 05:34:36
回答 3查看 1.8K关注 0票数 3

好的,这里是这样的:我有在C#中工作的代码,但是当我从PowerShell调用它时,它会失败。我不太清楚,但这是PowerShell特有的东西。下面是从C#调用库的相关代码(假设您提前添加了一个引用):

代码语言:javascript
复制
public class Test {
   [STAThread]
   public static void Main()
   {
      Console.WriteLine(  PoshWpf.XamlHelper.RoundTripXaml(
           "<TextBlock Text=\"{Binding FullName}\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"/>"
      ) );
   }
}

编译成可执行文件,很好.但是,如果您从PowerShell调用该方法,它将返回文本不带{Binding FullName}

代码语言:javascript
复制
add-type -path .\PoshWpf.dll
[PoshWpf.Test]::Main()

我已经粘贴到库的整个代码下面,所有代码都封装在一个PowerShell添加类型调用中,所以您只需将其粘贴到PowerShell中就可以编译它(如果您想将第一行和最后一行粘贴到Visual中的一个新控制台应用程序中)。

要作为可执行文件输出(从PowerShell 2),只需将-OutputType参数更改为ConsoleApplication,将-OutputAssembly更改为PoshWpf.exe (或其他东西)即可。因此,您可以看到,从可执行文件中运行相同的代码将为您提供正确的输出。

但是,运行上面这两行代码或者从[PoshWpf.XamlHelper]::RoundTripXaml [PoshWpf.XamlHelper]::ConvertToXaml 手动调用或似乎根本不起作用. HELP?!

代码语言:javascript
复制
Add-Type -TypeDefinition @"

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace PoshWpf
{
    public class Test {
       [STAThread]
       public static void Main()
       {
          Console.WriteLine(  PoshWpf.XamlHelper.RoundTripXaml(
               "<TextBlock Text=\"{Binding FullName}\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"/>"
          ) );
       }
    }

   public class BindingTypeDescriptionProvider : TypeDescriptionProvider
   {
      private static readonly TypeDescriptionProvider _DEFAULT_TYPE_PROVIDER = TypeDescriptor.GetProvider(typeof(Binding));

      public BindingTypeDescriptionProvider() : base(_DEFAULT_TYPE_PROVIDER) { }

      public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
      {
         ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
         return instance == null ? defaultDescriptor : new BindingCustomTypeDescriptor(defaultDescriptor);
      }
   }

   public class BindingCustomTypeDescriptor : CustomTypeDescriptor
   {
      public BindingCustomTypeDescriptor(ICustomTypeDescriptor parent) : base(parent) { }

      public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
      {
         PropertyDescriptor pd;
         var pdc = new PropertyDescriptorCollection(base.GetProperties(attributes).Cast<PropertyDescriptor>().ToArray());
         if ((pd = pdc.Find("Source", false)) != null)
         {
            pdc.Add(TypeDescriptor.CreateProperty(typeof(Binding), pd, new Attribute[] { new DefaultValueAttribute("null") }));
            pdc.Remove(pd);
         }
         return pdc;
      }
   }

   public class BindingConverter : ExpressionConverter
   {
      public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
      {
         return (destinationType == typeof(MarkupExtension)) ? true : false;
      }
      public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
      {
         if (destinationType == typeof(MarkupExtension))
         {
            var bindingExpression = value as BindingExpression;
            if (bindingExpression == null) throw new Exception();
            return bindingExpression.ParentBinding;
         }

         return base.ConvertTo(context, culture, value, destinationType);
      }
   }

   public static class XamlHelper
   {
      static XamlHelper()
      {
         // this is absolutely vital:
         TypeDescriptor.AddProvider(new BindingTypeDescriptionProvider(), typeof(Binding));
         TypeDescriptor.AddAttributes(typeof(BindingExpression), new Attribute[] { new TypeConverterAttribute(typeof(BindingConverter)) });
      }

      public static string RoundTripXaml(string xaml)
      {
         return XamlWriter.Save(XamlReader.Parse(xaml));
      }

      public static string ConvertToXaml(object wpf)
      {
         return XamlWriter.Save(wpf);
      }
   }
}



"@ -language CSharpVersion3 -reference PresentationCore, PresentationFramework, WindowsBase -OutputType Library -OutputAssembly PoshWpf.dll

同样,只需修改最后一行就可以得到一个可执行文件,如下所示:

代码语言:javascript
复制
"@ -language CSharpVersion3 -reference PresentationCore, PresentationFramework, WindowsBase -OutputType ConsoleApplication -OutputAssembly PoshWpf.exe
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-11-14 16:40:35

经过这么长一段时间(考虑到这个问题有多少视图),值得再次注意的是,这是固定的PowerShell 3中的 --我不确定这是因为他们修复了一个bug,还是因为PS3运行在.Net CLR 4上或什么的。

无论如何,如果将System.Xaml添加到-reference程序集列表中,那么原始问题中的代码将与PowerShell 3和4中的代码一样工作。

票数 1
EN

Stack Overflow用户

发布于 2010-03-23 14:56:07

我不是powershell dev,但您是否尝试过用`来转义{}?也许它是想变得聪明,并将绑定评估为一个powershell表达式?

票数 0
EN

Stack Overflow用户

发布于 2010-03-23 17:11:18

我对您在XamlHelper的类型初始化器中所做的TypeConverter设置有点困惑。BindingConverter应该做什么?您是否打算按照它在WPF中通常处理的方式处理{Binding}标记扩展?

在任何情况下,标记扩展都不能通过设计的XAML往返。以下摘录自有关XAML序列化限制的MSDN页面

序列化过程将取消对由各种标记扩展格式(如StaticResource或Binding )生成的对象的常见引用。在应用程序运行时创建内存中的对象时,它们已经被取消引用,而且Save逻辑不会重新访问原始的XAML来恢复对序列化输出的引用。这可能会冻结任何数据库或资源获取的值,使其成为运行时表示的最后一次使用的值,仅具有有限的或间接的能力来区分此值与本地任何其他值集。图像也被序列化为对项目中存在的图像的对象引用,而不是原始源引用,从而丢失了最初引用的任何文件名或URI。即使在同一页中声明的资源也会被序列化到被引用的位置,而不是作为资源集合的键保存下来。

考虑到这一点,我不知道为什么它应该在编译的应用程序中工作。但是正如我所说的,我必须承认我不知道你在用TypeConverter做什么,所以也许你已经解决了上面的限制。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2486076

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档