Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
224 views
in Technique[技术] by (71.8m points)

c# - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...