pt12lol
pt12lol

Reputation: 2441

Catastrophic failure in xaml binding

I am developing Windows 10 Universal App. I have code below:

xaml:

<Page
    x:Class="MyProject.BlankPage1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyProject"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
>
    <ItemsControl ItemsSource="{Binding}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Background="Purple"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding X}"/>
                <Setter Property="Canvas.Top" Value="{Binding Y}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Rectangle Fill="Red" Width="50" Height="50"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Page>

and code behind:

namespace MyProject
{
    public sealed partial class BlankPage1 : Page
    {
        public BlankPage1()
        {
            DataContext =
                new[]
                {
                    new { X = 50.0, Y = 100.0 },
                    new { X = 220.0, Y = 170.0 }
                };
            InitializeComponent();
        }
    }
}

Unfortunatelly, the rectangles does not show in the window. I am getting compilation error:

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

Assigning to Canvas coordinates static numbers in xaml works as expected.

Why error occurs and code does not work?

Upvotes: 1

Views: 1755

Answers (1)

Ren&#233; Sackers
Ren&#233; Sackers

Reputation: 2635

I just stumbled upon this issue myself, while building a Universal Windows Platform app.

Did some googling, found this article.

It was very helpful. I copied his SetterValueBindingHelper class into my own project. After that, I made 1 adjustment, because

type = System.Type.GetType(item.Type).GetTypeInfo();

gave an exception when you do Type="Canvas" in the XAML binding. It first tries to find the class Canvas in the current assembly. This returns null, and then it calls .GetTypeInfo() throwing a NullReferenceException.

Implemented C# 6.0's new Null-Conditional Operator on it, and that solved this issue. The code immediately after checks if type is null, and then goes through all loaded assemblies to find the Canvas.

type = System.Type.GetType(item.Type)?.GetTypeInfo();

His second usage example is oddly specifically related to using it with a Canvas element.

Another example from my Project VisualDesigner:

Here's my final XAML, based on his example:

<ItemsControl Grid.Column="1" ItemsSource="{Binding CanvasItems}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="helpers:SetterValueBindingHelper.PropertyBinding">
                <Setter.Value>
                    <helpers:SetterValueBindingHelper>
                        <helpers:SetterValueBindingHelper Type="Canvas" Property="Left" Binding="{Binding WindowX, Mode=TwoWay}" />
                        <helpers:SetterValueBindingHelper Type="Canvas" Property="Top" Binding="{Binding WindowY, Mode=TwoWay}" />
                    </helpers:SetterValueBindingHelper>
                </Setter.Value>
            </Setter>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <applicationwindow:ApplicationWindow Width="{Binding WindowWidth}" Height="{Binding WindowHeight}" DataContext="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

helpers: refers to the namespace the SetterValueBindingHelper is in. ApplicationWindow in my case is a custom UserControl. CanvasItems is an ObservableCollection<ApplicationWindowViewModel>, and this is my ApplicationWindowViewModel:

[ImplementPropertyChanged]
public class ApplicationWindowViewModel : ViewModelBase
{
    public string Title { get; set; }

    public double WindowX { get; set; } = 10;

    public double WindowY { get; set; } = 10;

    public int WindowWidth { get; set; } = 300;

    public int WindowHeight { get; set; } = 200;
}

In this example I use Fody.PropertyChanged to handle the property changed events on the X/Y/Width/Height properties, if you're not using this package, don't forget to implement your own PropertyChanged event handlers, etc.

Upvotes: 1

Related Questions