2010-03-21 25 views
3

好的,這裏是處理:我有代碼在C#中工作,但是當我從PowerShell調用它時,它失敗。我無法弄清楚,但它是PowerShell特有的。下面是相關的代碼調用從C#庫(假設你已經添加的時間提前參考):序列化WPF數據模板和{綁定表達式}(來自PowerShell?)

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}

add-type -path .\PoshWpf.dll 
[PoshWpf.Test]::Main() 

我已經貼在庫中的全部代碼下面,都在PowerShell中添加型呼叫包裹起來,以便您可以只需將其粘貼到PowerShell的編譯(可以去掉第一個和最後一個行如果你想將它粘貼到一個新的控制檯應用程序在Visual Studio中

要輸出(從PowerShell 2)作爲可執行文件,只需將-OutputType參數更改爲ConsoleApplication,並將-OutputAssembly更改爲PoshWpf.exe(或其他) 。因此,您可以看到,從可執行文件運行SAME CODE可以爲您提供正確的輸出。

但運行上述兩行或從PowerShell手動調用[PoshWpf.XamlHelper]::RoundTripXaml[PoshWpf.XamlHelper]::ConvertToXaml似乎根本沒有工作... 幫助?

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 

同樣,你可以得到由剛剛改變的最後一行,像這樣的可執行文件:

"@ -language CSharpVersion3 -reference PresentationCore, PresentationFramework, WindowsBase -OutputType ConsoleApplication -OutputAssembly PoshWpf.exe 
+0

順便提一下,現在我已經發布了,我注意到我沒有真正解釋這與DataTemplates有什麼關係:基本上,您必須生成XAML源以創建FrameworkTemplate任何類型 - 我試圖從已經創建的控件創建它們,所以我需要序列化回XAML來做到這一點。 – Jaykul 2010-03-21 05:47:32

+0

不知道您的直接問題,但您不需要使用XAML在WPF中創建DataTemplate(儘管您使用Silverlight。)在WPF中,您可以使用FrameworkElementFactory對象的樹,這些對象的基本描述符包括元素類型,財產製定者,兒童等等。但這並不是那裏,也不是那裏。想想這個。 – Josh 2010-03-23 14:45:08

+0

是的,我看了一下FrameworkElementFactory,但它有一點鈍,不推薦使用。我最關心的事情是相當簡單的模板,數據綁定僅限於像{Binding FullName}或{Binding Path = FullName}這樣的內容,如示例中所示 - 找到的代碼「有效」我真的喜歡使用它,並避免生成我自己的Xaml字符串;) – Jaykul 2010-03-24 06:38:00

回答

1

這段時間(並考慮這種觀點的問題都有一個號碼),這是值得回來,這裏要注意,這是固定的PowerShell 3後 - 我不知道這是因爲他們固定一個錯誤,或者如果它是因爲PS3運行在.Net CLR 4或什麼。

無論如何,如果你添加System.Xaml-reference組件列表中,在原有問題的代碼工作,在PowerShell中3和4。我想我會記住這爲答案,大多時候是這樣的人能阻止未來這裏試圖回答它;)

0

我不是PowerShell的開發,但你試過{}用`逃跑?也許它試圖變得聰明並將綁定評估爲PowerShell表達式?

+0

這是一個很好的想法。在我的測試案例中,爲了避免這些差異,我們將C#Main()方法中的{}插入到C#Main()方法中,並故意使用Console.WriteLine,以便它們不會被PowerShell解析的「輸出」在所有。 – Jaykul 2010-03-24 06:34:22

0

我對你在XamlHelper的類型初始化器中做的TypeConverter設置有點困惑。 BindingConverter應該做什麼?你打算如何處理{Binding}標記擴展,就像它通常在WPF中所做的那樣?

在任何情況下,標記擴展不能通過設計的XAML往返。從MSDN頁關於XAML serialization limitations以下摘錄:

由 各種標記擴展格式,例如 的靜態資源或綁定,由對象的公共引用將被序列化 過程 取消引用。這些已經 解除引用那個 在內存中的對象是由 應用程序運行時創建的時間,並保存 邏輯不回到原來的 XAML恢復到 串行輸出這種提法。這潛在地 凍結任何數據綁定或資源 獲得的值以與只有有限的或間接的能力 從本地設置任何其他 值區分這樣一個值使用的運行時間表示, 最後 的值。圖像 也序列化爲對象引用 到的圖像,因爲他們在 項目中存在,而不是作爲原始 源引用,失去任何 文件名或URI原是 引用。即使資源宣佈在同一頁內 被視爲 序列化爲他們 被引用的,而不是被保存 作爲資源 收集

考慮到的一個關鍵點,我不知道爲什麼它甚至應該在編譯的應用程序中工作。但正如我所說的,我必須承認我不確定你在用TypeConverter做什麼,所以你可能已經解決了上述限制。

+0

BindingConverter爲綁定表達式提供了保存邏輯(無需關心「源」本身),現在這對於我正在做的事情來說是完美的...因爲我們希望稍後設置源。 – Jaykul 2010-03-24 06:29:12

+0

順便提一句,BindingCustomTypeDescriptor和BindingTypeDescriptionProvider實際上確實嘗試序列化源以防它是一個靜態引用,但是我還沒有真正有什麼有用的示例,我會在哪裏使用它(即:在哪裏它將有意義往返),所以我現在還沒有真正使用它。 – Jaykul 2010-03-24 06:29:28

+0

檢查這些以獲取BindingConverter的更多詳細信息 - http://www.codeproject.com/KB/WPF/xamlwriterandbinding.aspx和http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a1984451 -4840-4e0f-abc5-8a8e34a4f8ca – akjoshi 2010-07-08 07:17:07