【问题标题】:Getting an XamlObjectWriterException only at design time with MultiBindingConverter (Visual Studio 2015)仅在设计时使用 MultiBindingConverter (Visual Studio 2015) 获取 XamlObjectWriterException
【发布时间】:2016-11-23 11:11:25
【问题描述】:

我已经缩小了原因,因为我使用 MultiBindingConverter 来计算变换中使用的角度。

我已将其精简到尽可能少。这是我的列表框的代码:

<Window.Resources>
    <x:Array Type="{x:Type sys:Int32}" x:Key="Cards">
        <sys:Int32>2</sys:Int32>
        <sys:Int32>4</sys:Int32>
        <sys:Int32>3</sys:Int32>
        <sys:Int32>5</sys:Int32>
        <sys:Int32>1</sys:Int32>
    </x:Array>
    <local:FanPositionCalculator x:Key="FanPositionCalculator"/>
</Window.Resources>
<ListView ItemsSource="{StaticResource Cards}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" BorderBrush="Black" Padding="5,25,55,15">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid RenderTransformOrigin="0.5,0.5">
                <Grid.RenderTransform>
                    <RotateTransform>
                        <RotateTransform.Angle>
                            <MultiBinding Converter="{StaticResource FanPositionCalculator}">
                                <Binding Source="{StaticResource Cards}"/>
                                <Binding Path=""/>
                            </MultiBinding>
                        </RotateTransform.Angle>
                    </RotateTransform>
                </Grid.RenderTransform>
                <TextBlock Text="Test"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

多重绑定根据其索引的计算将内容扇出。为此,我使用了多重绑定转换器:

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        int count = (values[0] as IList).Count;
        int itemIndex = (values[0] as IList).IndexOf(values[1]);

        double indexFromCenter = itemIndex - count / 2;

        //multiply by the degrees we want for each card
        return indexFromCenter * 3;
    }

传递的第一个值是对象列表。第二个是有问题的对象。它计算旋转它的角度。

当我运行它时它工作正常:

但是,它会在设计时杀死整个设计师:

错误是 XamlObjectWriterException:

Collection property 'System.Windows.Data.Binding'.'Source' is null.

at System.Xaml.XamlObjectWriter.WriteGetObject()
at System.Xaml.XamlWriter.WriteNode(XamlReader reader)
at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)

我不知道如何解决。我的转换器中没有错误,但它的存在导致此错误发生在列表所在的窗口中(而不是列表本身!)。关于如何解决它的任何想法?我想知道我是否可以在设计时跳过使用转换器。我对显示未轮换的卡片感到满意……但我对整个设计师都死去并不满意,所以我想解决它。我正在使用 Visual Studio 2015。

【问题讨论】:

    标签: wpf visual-studio xaml


    【解决方案1】:

    我不知道如何单步执行 XamlLoader 代码来查看它,但根据我在 this question 中观察到的情况,我认为其中存在错误。
    在解析 xaml 时,XamlLoader 会在元素上递归,同时维护上下文堆栈。当它递归到 Resources 元素时,它通过读取 xaml 并在该上下文中设置值(立即或作为延迟值)来建立 Cards 数组的值。然后它弹出堆栈并继续解析。当它在 ListView 上递归时,它会创建一个新的上下文,但该上下文似乎没有接收到静态资源的值。同时,XamlLoader 假定它具有并将未设置的(空)值写入接收属性(在您的情况下为绑定源),这会导致错误。

    换句话说,WPF 似乎(无论如何对我来说)对在一个解析上下文中设置并在另一个解析上下文中使用的值感到困惑。解决方法是最小化不同的上下文。在您的情况下,这意味着在 ListView 而不是 Window 上设置资源。 ItemsSource 需要使用 Object Element Syntax 进行设置,然后您可以使用 RelativeSource 对其进行引用。我也喜欢在元素资源中实例化RelativeSource,因为我认为它更简洁。

    <ListView HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" BorderBrush="Black" Padding="5,25,55,15">
        <ListView.Resources >
            <RelativeSource x:Key="List" Mode="FindAncestor" 
                        AncestorType="{x:Type ListView}" />
            <local:FanPositionCalculator x:Key="FanPositionCalculator"/>
        </ListView.Resources>
        <ListView.ItemsSource>
            <x:Array Type="{x:Type system:Int32}" x:Name="Cards">
                <system:Int32>2</system:Int32>
                <system:Int32>4</system:Int32>
                <system:Int32>3</system:Int32>
                <system:Int32>5</system:Int32>
                <system:Int32>1</system:Int32>
            </x:Array>
        </ListView.ItemsSource>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid RenderTransformOrigin="0.5,0.5">
                    <Grid.RenderTransform>
                        <RotateTransform>
                            <RotateTransform.Angle>
                                <MultiBinding Converter="{StaticResource FanPositionCalculator}">
                                    <Binding RelativeSource="{StaticResource List}" Path="ItemsSource"/>
                                    <Binding Path=""/>
                                </MultiBinding>
                            </RotateTransform.Angle>
                        </RotateTransform>
                    </Grid.RenderTransform>
                    <TextBlock Text="Test"/>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    我正在使用 VS 2017 RC,这为我修复了设计视图,并为 VS 2013 修复了相同的结果,因此,应该也适用于您。

    【讨论】:

    • 干得好!没想到会解决这个问题。我已经放弃了。有一件事,直接绑定到 multibinind 中 ListView 的 ItemsSource 可能更简单,而不是创建一个 ListView 资源来保存它自己的 ItemsSource: 。这完全避免了整个资源的事情。
    • 嘿@Joe:不用担心,是的,真实的数据。我并没有真正考虑我猜想的基本内容,我的大脑在试图追踪 XamlObjectWriter。
    • 使用 XAML 标记语法RelativeSource 标记扩展实例化为资源的天才。对此表示敬意。但是,正如您所说,您发明的那部分(至少)似乎不需要“使用对象元素语法设置ItemsSource [be]”。一旦您使用该技巧逃脱了模板并绑定到ListView(这是最困难的部分),那么使用什么XAML 语法来建立该实例的ItemsSource 就无关紧要了,对吧?或者你是在用那句话来解决 OP 问题的不同部分吗?再次,出色的工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多