Reputation: 2441
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
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