tags:

views:

63

answers:

5

I want to bind a user control (View) to a ListBoxItem. The ListBox is bound to a collection of ViewModels. I have set the ListBox's ItemTemplate as so:

<ListBox.ItemTemplate>
     <DataTemplate>
           <View:ContactView/>     
     </DataTemplate>
 </ListBox.ItemTemplate>

But all I get are blank ListBoxItems. I can click on them, but nothing is showing visually. My ContactView code is very simply:

<Border>
    <DockPanel>
        <StackPanel DockPanel.Dock="Right" Orientation="Vertical">
            <TextBlock Text="{Binding Path=ContactFirstName, FallbackValue=FirstName}" FontWeight="Bold" Margin="5, 0, 5, 0"></TextBlock>
            <TextBlock Text="{Binding Path=ContactLastName, FallbackValue=LastName}" FontWeight="Bold" Margin="5, 0, 5, 0"></TextBlock>
            <TextBlock Text="{Binding Path=ContactNumber, FallbackValue=Number}" Margin="5, 0, 5, 0"></TextBlock>
        </StackPanel>
    </DockPanel>
</Border>

What could be wrong with this? Thanks.

+1  A: 

Your ContactView is not 'inheriting' the data context of the ItemTemplate. Or, rather, the ContactView itself is, but the "inner" controls are separate. Try:

<View:ContactView DataContext="{Binding Path=.}" />

Path=. is a special construct meaning "the current element." You can even shorten it to just {Binding} I think.

If you check the output window, you should have a bunch of errors saying how no object was provided for those TextBlock bindings.

JustABill
No difference. I did set the DataContext of the ContactView already in in the main ContactView file - surely that does the same thing?And there's no errors at all in the output window, I checked there earlier.
Harry
Strange. If you follow some of the methods at http://beacosta.com/blog/?p=52 do you get any errors? And yes, that would do the same thing - it just wasn't specified in your post.
JustABill
OK, I ran the converter first and it came back with the result as null. I also did the trace output and it does seem that the DataContext is set to null... The trace does output saying it found the accessor for the string property in the ContactViewModel class. Only, it then outputs saying "Transfer Value - got raw value <null>". I'm guessing that's not a good thing.
Harry
+1  A: 

Did you set the ItemSource property?

ItemsSource="{Binding}"
John
Yes, ItemsSource has been correctly set.
Harry
A: 

Use Binding Like

<View:NameofControl DataContext="{Binding }" />
Johnny
See the post two above yours...
Harry
A: 

When do your ViewModels set their properties? It could be that the Binding reads all values as null (before data is set) - and then receives no notification when data is actually set.

Goblin
Set in the constructor. All properties are set with the OnPropertyChanged() method called. And I'm using an ObservableCollection so any items added to the collection will (should) appear.
Harry
A: 

Seem to work fine with my sample project:

Window1 XAML:

<Window x:Class="WpfApplication7.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:WpfApplication7="clr-namespace:WpfApplication7"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <ListBox x:Name="myListbox">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <WpfApplication7:ContactView/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

ContactView XAML (no code behind needed ;)):

<UserControl x:Class="WpfApplication7.ContactView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <Border>
        <DockPanel>
            <StackPanel DockPanel.Dock="Right" Orientation="Vertical">
                <TextBlock Text="{Binding Path=ContactFirstName, FallbackValue=FirstName}" FontWeight="Bold" Margin="5, 0, 5, 0"></TextBlock>
                <TextBlock Text="{Binding Path=ContactLastName, FallbackValue=LastName}" FontWeight="Bold" Margin="5, 0, 5, 0"></TextBlock>
                <TextBlock Text="{Binding Path=ContactNumber, FallbackValue=Number}" Margin="5, 0, 5, 0"></TextBlock>
            </StackPanel>
        </DockPanel>
    </Border>

</UserControl>

Code behind for Window1:

public partial class Window1
{
    public Window1()
    {
        InitializeComponent();
        myListbox.ItemsSource = new[]
                                    {
                                        new Contact { ContactFirstName = "Stack", ContactLastName = "Overflow", ContactNumber = 1 },
                                        new Contact { ContactFirstName = "Stack", ContactLastName = "Overflow", ContactNumber = 2 },
                                        new Contact { ContactFirstName = "Stack", ContactLastName = "Overflow", ContactNumber = 3 },
                                    };
    }
}

public class Contact
{
    public string ContactFirstName { get; set; }
    public string ContactLastName { get; set; }
    public int ContactNumber { get; set; }
}

I think your problem lies with the items in your ItemsSource. Make sure you bind to the correct property. My Contact objects have the correct properties. Perhaps your objects in your ItemsSource have different property names? Or do those objects have a property to Contact which holds the properties you want?

If you have a Contact property in your ItemsSource objects, you can use a binding as follows on the TextBlock (notice the dot):

<TextBlock Text="{Binding Path=Contact.FirstName}" FontWeight="Bold" Margin="5, 0, 5, 0"></TextBlock>

Hope this helps a bit pin pointing where your problem lies!

Arcturus
I see no real difference to what I'm doing and what you've done there. There are no errors with where the bindings are wired to. I'd get an error in the output window if I wasn't binding to the correct location, so I know that I definitely am. I've debugged the ViewModel and the properties are definitely showing the correct values. I am calling OnPropertyChanged on set, so the binds will update. I just see nothing wrong...
Harry
Are the properties also retrieved? Try putting a breakpoint on the get, to see if they are really being retrieved..
Arcturus
It's weird... It's setting them as it should, but when it goes to retrieve the values they're null...
Harry
OK, I stepped through the code and I found the problem. I was setting the DataContext to a new instance of ContactViewModel, so when the MainView was creating a new instance of ContactView, a new instance was also being created for ContactViewModel... which was why the values were null! Such a silly problem, and really shouldn't have taken all this effort lol. Anyway, thanks very much.
Harry
No problem.. :)
Arcturus