XAML GridView ItemTemplate not binding to control
I have a GridView with an ItemTemplate that holds a Custom control:
<GridView
ItemsSource="{Binding Ubicaciones.Ubicaciones}">
<GridView.ItemTemplate>
<DataTemplate>
<ctr:HabitacionControl
Width="70"
Height="140"
Ubicacion="{Binding}"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
And here is my custom user control:
<UserControl
x:Class="MySln.Mucama.Controls.HabitacionControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MySln.Mucama.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="200"
d:DesignWidth="97">
<UserControl.DataContext>
<local:HabitacionControlVM/>
</UserControl.DataContext>
<Grid>
<RelativePanel>
<Image x:Name="Puerta" Source="ms-appx:///Assets/Puerta.jpg"
Grid.RowSpan="5"/>
<TextBlock Text="{Binding Ubicacion.StrNombreMesa,FallbackValue=####}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="AliceBlue"
FontWeight="ExtraBold"
RelativePanel.AlignHorizontalCenterWithPanel="True"/>
</RelativePanel>
</Grid>
</UserControl>
And its code behind:
public sealed partial class HabitacionControl : UserControl
{
public HabitacionControl()
{
this.InitializeComponent();
}
public MyClass Ubicacion
{
get { return (MyClass)GetValue(UbicacionProperty); }
set { SetValue(UbicacionProperty, value); }
}
// Using a DependencyProperty as the backing store for Ubicacion. This enables animation, styling, binding, etc...
public static readonly DependencyProperty UbicacionProperty =
DependencyProperty.Register("Ubicacion", typeof(MyClass), typeof(HabitacionControl), new PropertyMetadata(new PropertyChangedCallback(OnUbicacionChanged)));
private static void OnUbicacionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//...
}
}
Now I need to bind each Ubicaciones.Ubicaciones to the Ubicación property of my Customcontrol.
At run time my gridview generates all my items, but binding to its Ubicacion property never happens.
There aren't any warnings in the output window.
What I'm missing? Or doing wrong?
My my, look at this here:
<UserControl.DataContext>
<local:HabitacionControlVM/>
</UserControl.DataContext>
Someone sold you a bill of dirty, filthy, goods. Probably one of those jerks who run around telling people DataContext = this;
is a good idea.
Sorry, tangent. Now look at this:
<ctr:HabitacionControl
Width="70"
Height="140"
Ubicacion="{Binding}"/>
What is that I'm seeing? Is that a pseudo-DataContext property? That's a pseudo-DataContext property. The problem is that the Binding
works against the object within the DataContext of the HabitacionControl
not its parent. And what's the DataContext of the HabitacionControl
?
<UserControl.DataContext>
<local:HabitacionControlVM/>
</UserControl.DataContext>
And that's why you don't create view models for your UserControls. You have broken how data binding works. The view model must flow down the visual tree through the DataContext. When you interrupt this flow, you get fail.
Let me ask you--does a TextBox have a TextBoxViewModel? No. It has a Text
property that you bind to. How do you bind to it? Your view model flows into TextBox.DataContext
, thus allowing you to bind properties of your view model to properties exposed on the TextBox.
There are other hacky ways to get around this, but the best solution is to not get yourself into this situation in the first place.
You need to ditch that HabitacionControlVM
and expose DependencyProperties on the surface of your UserControl that your view model can bind against, providing whatever your UserControl needs in order to function. Place your UI logic in the codebehind of HabitacionControl
.
No, this doesn't break MVVM. UI logic is fine in the codebehind.
If your HabitacionControlVM
is performing heavy lifting that really shouldn't be in the codebehind, then just refactor it into classes that your codebehind calls into.
People think the UserControlViewModel anti-pattern is how it should be done. It really isn't. Good luck.