none
相当【诡异】的一个关于ItemsControl套ItemsControl, 里层ItemsControl的ItemTemplate不能同时应用Converter和事件的问题 RRS feed

  • 问题

  • 各位大侠好:

    最近在做一个比较复杂的数据控件时遇到了一个很诡异的问题

    控件的结构是一个ItemsControl套一个ItemsControl, 里层ItemsControl的ItemTemplate内如果同时应用Converter和注册事件就会报空引用的错误, 具体如下:

    新建一个WPF工程, 前台代码如下

     

    <Window x:Class="Test_ConverterNull.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:Test_ConverterNull"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <BooleanToVisibilityConverter x:Key="conv_BooleanToVisibility"/>
        </Window.Resources>
        <Grid>
            <ScrollViewer>
                <ItemsControl ItemsSource="{Binding Mode=OneWay}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <ListBox ItemsSource="{Binding Mode=OneWay}">
                                <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <StackPanel>
                                            <CheckBox x:Name="cb"/>
                                            <TextBlock Visibility="{Binding IsChecked, ElementName=cb, Converter={StaticResource conv_BooleanToVisibility}, Mode=OneWay}" Text="Hello" Loaded="TextBlock_Loaded"/>
                                        </StackPanel>
                                    </DataTemplate>
                                </ListBox.ItemTemplate>
                            </ListBox>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </ScrollViewer>
        </Grid>
    </Window>
    
    

     


    后台代码仅仅创建了数据集合且绑定

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace Test_ConverterNull
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            List<List<string>> datas = new List<List<string>>();
            public MainWindow()
            {
                InitializeComponent();
    
                datas = new List<List<string>>();
                for (int i = 0; i < 10; i++)
                {
                    List<string> data = new List<string>();
                    for (int j = 0; j < 5; j++)
                    {
                        data.Add(Guid.NewGuid().ToString());
                    }
                    datas.Add(data);
                }
    
                this.DataContext = datas;
            }
    
            private void TextBlock_Loaded(object sender, RoutedEventArgs e)
            {
    
            }
        }
    }
    

     


    如此运行的话就会出现如下错误

    错误堆栈:

       在 Test_ConverterNull.MainWindow.System.Windows.Markup.IStyleConnector.Connect(Int32 connectionId, Object target) 位置 c:\Users\Tale Xu\Documents\Visual Studio 2010\Projects\Test_ConverterNull\Test_ConverterNull\MainWindow.xaml:行号 19

       在 System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)

       在 System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter)

       在 System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)

       在 System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren)

       在 System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)

       在 System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)

       在 System.Windows.FrameworkElement.ApplyTemplate()

       在 System.Windows.FrameworkElement.MeasureCore(Size availableSize)

       在 System.Windows.UIElement.Measure(Size availableSize)

       在 System.Windows.Controls.StackPanel.MeasureOverride(Size constraint)

       在 System.Windows.FrameworkElement.MeasureCore(Size availableSize)

       在 System.Windows.UIElement.Measure(Size availableSize)

       在 System.Windows.ContextLayoutManager.UpdateLayout()

       在 System.Windows.UIElement.UpdateLayout()

       在 System.Windows.Interop.HwndSource.SetLayoutSize()

       在 System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)

       在 System.Windows.Interop.HwndSource.set_RootVisual(Visual value)

       在 System.Windows.Window.SetRootVisual()

       在 System.Windows.Window.SetRootVisualAndUpdateSTC()

       在 System.Windows.Window.SetupInitialState(Double requestedTop, Double requestedLeft, Double requestedWidth, Double requestedHeight)

       在 System.Windows.Window.CreateSourceWindow(Boolean duringShow)

       在 System.Windows.Window.CreateSourceWindowDuringShow()

       在 System.Windows.Window.SafeCreateWindowDuringShow()

       在 System.Windows.Window.ShowHelper(Object booleanBox)

       在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)

       在 MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

       在 System.Windows.Threading.DispatcherOperation.InvokeImpl()

       在 System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)

       在 System.Threading.ExecutionContext.runTryCode(Object userData)

       在 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)

       在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)

       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

       在 System.Windows.Threading.DispatcherOperation.Invoke()

       在 System.Windows.Threading.Dispatcher.ProcessQueue()

       在 System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

       在 MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

       在 MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)

       在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)

       在 MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

       在 System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)

       在 MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

       在 MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)

       在 System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)

       在 System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)

       在 System.Windows.Application.RunDispatcher(Object ignore)

       在 System.Windows.Application.RunInternal(Window window)

       在 System.Windows.Application.Run(Window window)

       在 System.Windows.Application.Run()

       在 Test_ConverterNull.App.Main() 位置 C:\Users\Tale Xu\Documents\Visual Studio 2010\Projects\Test_ConverterNull\Test_ConverterNull\obj\x86\Debug\App.g.cs:行号 0

       在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)

       在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

       在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

       在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)

       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)

       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

       在 System.Threading.ThreadHelper.ThreadStart()

    ----------

    将前台中的Converter或Loaded事件中的任何一个去掉都正常, 运行效果入下图

    请问这是什么情况? 是WPF固有bug还是我哪里弄的不对, 谢谢!
    • 已编辑 Tale Xu 2011年12月9日 8:43 补充信息
    2011年12月9日 8:40

答案

  • 这个是template解析的问题,解决方案:

    <Grid>
        <ScrollViewer>
            <ItemsControl ItemsSource="{Binding Mode=OneWay}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <DataTemplate.Resources>
                            <BooleanToVisibilityConverter x:Key="conv_BooleanToVisibility"/>
                            <DataTemplate x:Key="template">
                                <StackPanel>
                                    <CheckBox x:Name="cb"/>
                                    <TextBlock Visibility="{Binding IsChecked, ElementName=cb, Converter={StaticResource conv_BooleanToVisibility}, Mode=OneWay}" Loaded="TextBlock_Loaded" Text="Hello">
                                    </TextBlock>
                                </StackPanel>
                            </DataTemplate>
                        </DataTemplate.Resources>
                        <ListBox ItemTemplate="{StaticResource template}" ItemsSource="{Binding Mode=OneWay}">
                        </ListBox>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>

     

     


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 Tale Xu 2011年12月13日 3:56
    2011年12月12日 5:41
    版主

全部回复

  • 大侠们, 没人回复吗...
    2011年12月11日 8:13
  • 这个问题在 .Net3.5 里是没有的,只有 .Net4 才有。我不知道是什么原因,所以只能提供一个临时解决办法,那就是既然报空那咱们就判断一下是不是 null 不就行了么。找到 obj 文件夹下面 Debug 子文件夹中的 MainWindow.g.cs 文件,找到里面的

    #line 15 "..\..\..\MainWindow.xaml"
    ((System.Windows.Controls.TextBlock)(target)).Loaded += new System.Windows.RoutedEventHandler(this.TextBlock_Loaded);

    这两行。改成:

    if (target != null)
    {
        #line 15 "..\..\..\MainWindow.xaml"
        ((System.Windows.Controls.TextBlock)(target)).Loaded += new System.Windows.RoutedEventHandler(this.TextBlock_Loaded);
    }

    但是我觉得这个方法没有解决根本问题吧, 这样和我在前台不注册Loaded事件无异了, 依然是不能Converter和事件共存
    2011年12月11日 11:37
  • 不一样的,在前台不注册 Loaded 那你就没有 Loaded 事件了吗。这个解决方法是可以共存的。不信你往 Loaded 里放个 MessageBox 就可以看出是不是共存了,这样做实际上事件还是可以触发的。
    2011年12月11日 12:11
  • private void TextBlock_Loaded(object sender, RoutedEventArgs e)
    {
        ((TextBlock)e.Source).Text = "x";
    }

    倒是确实会触发, 但是g.cs会随时被改回去, 总不能那么多地方, 每次一重新生成我还得再改一回吧

    2011年12月11日 12:54
  • 这个是template解析的问题,解决方案:

    <Grid>
        <ScrollViewer>
            <ItemsControl ItemsSource="{Binding Mode=OneWay}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <DataTemplate.Resources>
                            <BooleanToVisibilityConverter x:Key="conv_BooleanToVisibility"/>
                            <DataTemplate x:Key="template">
                                <StackPanel>
                                    <CheckBox x:Name="cb"/>
                                    <TextBlock Visibility="{Binding IsChecked, ElementName=cb, Converter={StaticResource conv_BooleanToVisibility}, Mode=OneWay}" Loaded="TextBlock_Loaded" Text="Hello">
                                    </TextBlock>
                                </StackPanel>
                            </DataTemplate>
                        </DataTemplate.Resources>
                        <ListBox ItemTemplate="{StaticResource template}" ItemsSource="{Binding Mode=OneWay}">
                        </ListBox>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>

     

     


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 Tale Xu 2011年12月13日 3:56
    2011年12月12日 5:41
    版主
  • 这个是template解析的问题,解决方案:

    <Grid>
        <ScrollViewer>
            <ItemsControl ItemsSource="{Binding Mode=OneWay}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <DataTemplate.Resources>
                            <BooleanToVisibilityConverter x:Key="conv_BooleanToVisibility"/>
                            <DataTemplate x:Key="template">
                                <StackPanel>
                                    <CheckBox x:Name="cb"/>
                                    <TextBlock Visibility="{Binding IsChecked, ElementName=cb, Converter={StaticResource conv_BooleanToVisibility}, Mode=OneWay}" Loaded="TextBlock_Loaded" Text="Hello">
                                    </TextBlock>
                                </StackPanel>
                            </DataTemplate>
                        </DataTemplate.Resources>
                        <ListBox ItemTemplate="{StaticResource template}" ItemsSource="{Binding Mode=OneWay}">
                        </ListBox>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>

     

     


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    谢谢版主, 问题成功解决了. 

    不过顺带问一下, 这个问题的根源是什么呢? 是像2楼所说, 由于自动生成的.g.cs文件有判空缺陷导致的吗?

    2011年12月13日 1:46
  • 不是,在我的回复中说了,是模板嵌套模板 xaml解析资源的时候会无法正确的解析资源,就是找不到正确的资源,所以会报错。


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年12月13日 5:51
    版主