2011-04-12 12 views
7

我完全按照Setting event handlers inside a Setter.Value structure中所述的方式面對問題。但我想明白爲什麼問題作者提供的解決方案不起作用。看起來我錯過了一些概念。爲什麼「在Setter.Value結構中設置事件處理程序」會產生編譯錯誤?

+0

通過*「由問題作者提供的解決方案」*您的意思只是它不起作用附加像這樣的處理程序,對不對? (只是爲了避免混淆,因爲我確實提供了一個「解決方案」,涉及使用'EventSetters',它可以工作) – 2011-04-12 12:04:31

+0

是的,你是對的。 – alehro 2011-04-12 12:19:58

回答

13

這似乎是XAML代碼隱藏代中的一個錯誤。除了用於XAML文件的用戶代碼隱藏之外,還有一個「編譯器」生成的版本,該版本爲命名元素(即x:Name)定義InitializeComponent和類字段。

給出一個簡單的例子:

<Window.Resources> 
    <Style TargetType="Button"> 
     <Setter Property="ContextMenu"> 
      <Setter.Value> 
       <ContextMenu> 
        <MenuItem Header="Header" Click="MenuItem_Click"/> 
       </ContextMenu> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Window.Resources> 

<Button /> 

如果你運行它,你會得到以下異常:

System.Windows.Markup.XamlParseException occurred 
    Message='Set connectionId threw an exception.' Line number '13' and line position '8'. 
    Source=PresentationFramework 
    LineNumber=13 
    LinePosition=8 
    StackTrace: 
     at System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri) 
    InnerException: System.InvalidCastException 
     Message=Unable to cast object of type 'System.Windows.Controls.MenuItem' to type 'System.Windows.Controls.Button'. 
     Source=Windows7Theme 
     StackTrace: 
      at Windows7Theme.MainWindow.System.Windows.Markup.IComponentConnector.Connect(Int32 connectionId, Object target) in c:\Users\TJoe\Documents\Visual Studio 10\Projects\Windows7Theme\Windows7Theme\MainWindow.xaml:line 13 
      at MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetConnectionId(Object root, Int32 connectionId, Object instance) 
     InnerException: 

生成的代碼隱藏文件可以在obj文件夾中找到,所以如果我們檢查,我們可以看到下面的代碼:

void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) { 
    switch (connectionId) 
    { 
    case 1: 

    #line 13 "..\..\..\MainWindow.xaml" 
    ((System.Windows.Controls.Button)(target)).AddHandler(System.Windows.Controls.MenuItem.ClickEvent, new System.Windows.RoutedEventHandler(this.MenuItem_Click)); 

    #line default 
    #line hidden 
    return; 
    } 
    this._contentLoaded = true; 
} 

的發行H ere是生成的代碼試圖將MenuItem轉換爲Button。如果我們改變我們的樣本,像這樣:

<Window.Resources> 
    <ContextMenu x:Key="ContextMenuKey"> 
     <MenuItem Header="Header" Click="MenuItem_Click"/> 
    </ContextMenu> 

    <Style TargetType="Button"> 
     <Setter Property="ContextMenu" 
       Value="{StaticResource ContextMenuKey}" /> 
    </Style> 
</Window.Resources> 

<Button /> 

然後生成的代碼是:

void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) { 
    switch (connectionId) 
    { 
    case 1: 

    #line 10 "..\..\..\MainWindow.xaml" 
    ((System.Windows.Controls.MenuItem)(target)).Click += new System.Windows.RoutedEventHandler(this.MenuItem_Click); 

    #line default 
    #line hidden 
    return; 
    } 
    this._contentLoaded = true; 
} 

根據我的測試中,它出現在代碼生成的ID分配給每個控件,它需要「連接「或爲其添加處理程序/後臺字段。在ContextMenu被內聯包含的情況下(即第一個例子),它的事件處理程序正被分配給窗口內的根元素並且沒有得到它自己的ID。

如果我們將Button更改爲包含在網格中,那麼上面的異常將表示它無法將MenuItem投射到網格。因爲現在網格是根元素。這表明它與Style對象的類型無關。

當ContextMenu作爲單獨的資源包含在內時,代碼生成器似乎正確地爲其分配了一個ID,因此可以正確連接處理程序。

最終,這是XAML代碼生成器中的一個錯誤。

+2

感謝您的精彩解釋。我認爲你可以將這個bug提交給wpf開發者。 – alehro 2011-04-13 10:29:12

相關問題