Databind in ListBox's DataTemplate

Sep 27, 2010 at 3:47 AM

Rob,

I am trying out Caliburn Micro. I'll join the echoes that your Mix talk was awesome; I fell in love with how cleanly-focused the app was on business logic given that almost all of the glue had been pushed into the framework. 

I am struggling to get Databinding working in a ListBox that has a DataTemplate. My UserListView.xaml looks like:

<ContentControl x:Class="CaliburnMicroWPF1.Views.UserListView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:svc="clr-namespace:MyService;assembly=MyService"
             mc:Ignorable="d" 
             xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
    d:DesignHeight="300" d:DesignWidth="300">
	
    <ContentControl.Resources>
		<DataTemplate x:Key="UserDataTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBox x:Name="FirstName" Text="{Binding FirstName}"></TextBox>
                <TextBox x:Name="LastName" Text="{Binding LastName}"></TextBox>
            </StackPanel>
        </DataTemplate>
	</ContentControl.Resources>
    
    <StackPanel Orientation="Vertical">
        <ListView x:Name="Users" ItemTemplate="{DynamicResource UserDataTemplate}">

        </ListView>
    </StackPanel>
</ContentControl>

And my UserListViewModel.cs looks like:

    public class UserListViewModel : PropertyChangedBase
    {
        public UserListViewModel()
        {
            UserDal dal = new UserDal();
            Users = new ObservableCollection<User>(dal.GetAllUsers());
        }

        public ObservableCollection<User> Users
        {
            get; set; 
        }
    }

When I remove the Binding expressions from the Text properties in the Xaml, I just get empty textboxes. I thought that the x:Name would take care of it by convention, but it does not appear to.

If I were to modify Caliburn Micro to support this scenario, would you recommend it? My best guess is that I'd modify ViewModelBinder and add logic to BindProperties to look deeper into templates referenced by the control. Or create convention somehow for ItemsControl to interrogate ItemTemplate.

Note I'm more interested in help with how to implement it than for you to do it for me, as I want to further my understanding of the framework.

Thanks,
Travis 

Coordinator
Sep 27, 2010 at 3:28 PM

There's a technical limitation in WPF/SL/WP7 in that there is no way to intercept template generation. So, while you can see the xaml in the template, those elements don't exist until the item gets generated by the ListBox, so there's no way to apply the conventions. To get around that, you can use the Bind.Model property on the root node inside the template. This will allow us to "hook" in to the template creation and apply the conventions. But, obviously, that dirties up the template a bit. The approach that I normally take is to use binding expressions on small templates and to factor larger templates into UserControls and then let the conventions take over. Sorry ;( I've been trying to explain this scenario to the WPF/SL teams, but I'm not sure they understand CoC just yet...

Sep 27, 2010 at 3:51 PM

Now that I know what to search for, I see you've answered this before: http://caliburn.codeplex.com/Thread/View.aspx?ThreadId=214908

It adds a little goop, yes, but less than I had before, and a billion times less than if I weren't using Caliburn Micro.

CoC is what made me really enjoy ASP.NET MVC development, and I'm so happy to see it here for the WPF/Silverlight world. 

Thanks for the reply,
Travis