1
votes

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?

1
You're missing an ItemsSource Binding for your ItemsControl. Though, setting the DataContext to an array is also somewhat odd; just for testing, I'm assuming?Dan Bryant
Off course it was, thanks for your advice.pt12lol
Please clarify: does the problem still occur now that you've added the ItemsSource binding to your control? If so, have you tried using a named type instead of an anonymous type? E.g. Tuple<double, double> or your own user-defined type? Have you tried seeing the Canvas.Left and Canvas.Top properties in the ItemTemplate instead of the content presenter's style?Peter Duniho
Still does not work and same results. Tried with user-defined type and content presenter style replaced with ItemTemplate properties. What do you mean by using Tuple<double, double>?pt12lol
Unfortunately, I don't have VS2015 yet and can't even attempt to reproduce your exact error. Given that you write that it's a "compilation error" (i.e. occurs before you can even run the program, never mind show a window), I don't see why you'd expect anything to "show in the window". That said, I have a vague recollection that you cannot specify a binding for a setter's Value in Winrt apps. It works in WPF, but not in Winrt. You may want to consider using Rectangle.RenderTransform to position your rectangles instead.Peter Duniho

1 Answers

1
votes

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.