none
ListBox/ItemsControl DataTemplate issue

    Question

  •  I have a ListBox with a DataTemplate as follows:

    <ListBox x:Name="procList" ItemsSource="{Binding}">

    <ListBox.ItemTemplate>

    <DataTemplate>

    <TextBlock Margin="10" Text="{Binding Path=Identifier}"/>

    </DataTemplate>

    </ListBox.ItemTemplate>

    </ListBox>

    This works fine, i.e. the DataTemplate is applied to my items as expected. However, if I use an ItemsControl instead of the ListBox, i.e.:

    <ItemsControl x:Name="procList" ItemsSource="{Binding}">

    <ItemsControl.ItemTemplate>

    <DataTemplate>

    <TextBlock Margin="10" Text="{Binding Path=Identifier}"/>

    </DataTemplate>

    </ItemsControl.ItemTemplate>

    </ItemsControl>

    .. the DataTemplate is not applied, i.e. the ItemsControl is filled with the rendered "bound" object themselves, instead of the wanted textbox.  I've tried different ways to apply the template in this case, but with no success.

    What is wrong ? Shouldn't the ListBox and the ItemsControl apply the DataTemplate in the same manner ?

    (The used datasource is an ObservableCollection filled with some very simple objects)

    Regards,
    Leif O

    Tuesday, November 28, 2006 12:25 PM

All replies

  • seems to work fine in RTM version
    Tuesday, November 28, 2006 2:37 PM
  • I'm using the RTM version.

    However, it looks to me that my real problem is the databinding, probably the ItemsSource part. If I e.g. bind my ItemsControl to some static system data and just display some dummy data in the template, e.g.:

    <ItemsControl x:Name="procList" ItemsSource="{Binding Source={x:Static g:DateTimeFormatInfo.CurrentInfo}, Path=DayNames}">

    <ItemsControl.ItemTemplate>

    <DataTemplate>

    <Button>dummy</Button>

    </DataTemplate>

    </ItemsControl.ItemTemplate>

    </ItemsControl>

    the template is applied correctly, i.e. I get 7 buttons for the example code above (if I display dummy data with my original binding, it still not work).  

    It therefore looks to me that the set-up of the databinding is different for ListBox and ItemsControl and that this setup affects the use of the DataTemplate. I'm quite new in the world of WPF so this puzzles me. Any reason why my working ListBox databinding shouldn't work the same when applied to an ItemsControl ?

    Regards,
    Leif O

     

    Tuesday, November 28, 2006 5:47 PM
  • Can you try this and see if this works

    <ItemsControl x:Name="procList" ItemsSource="{Binding}">

                  <ItemsControl.ItemTemplate>

                         <DataTemplate>

                               <TextBlock Margin="10" Text="{Binding Path=Name}"/>

                         </DataTemplate>

                  </ItemsControl.ItemTemplate>

           </ItemsControl>

    public partial class Window1 : System.Windows.Window

        {

     

            public Window1()

            {

                InitializeComponent();

                ObservableCollection<Customer> cc = new ObservableCollection<Customer>();

                for (int i = 0; i < 10; i++)

                    cc.Add(new Customer("customer " + i.ToString()));

                procList.DataContext = cc;

            }

     

        }

        public class Customer

        {

            private string _name;

     

            public string Name

            {

                get { return _name; }

                set { _name = value; }

            }

     

            public Customer(string n)

            {

                _name = n;

            }

        }

     

    Tuesday, November 28, 2006 5:57 PM
  • Thank you for your reply.

    Yes, your code works.

    However, if I make the Customer class an UIElement, the problem re-appears, so the issue is obviously related to binding UIElement objects to the ItemsControl. E.g. if I make the Customer a Button (and change the "Name" property to "NameX", to avoid name clash with the Button class):

    public class Customer : Button
    {
      
    private string _name;
      
    public string NameX
       {
         
    get { return _name; }
         
    set { _name = value; }
       }
      
    public Customer(string n)
       {
          _name = n;
       }
    }

    ..the code will display the Button UI in the ItemsControl instead of the templated text. If I use a ListBox instead, the code works. If I inherit from UIElement instead of Button, nothing at all is displayed in the ItemsControl. My own original bound class inherits from FrameworkElement, so this looks to be my problem.

    Is it not possible to use DataTemplates together with UIElement objects in an ItemsControl ?

    Regards,
    Leif O

    Wednesday, November 29, 2006 8:08 AM
  • As Customer is button, you have to style it

    <Style TargetType="{x:Type loc:Customer}">

    <Setter Property="Template">

    <Setter.Value>

    <ControlTemplate TargetType="{x:Type loc:Customer}">

    <TextBlock Margin="10" Text="{Binding Path=NameX}"/>

    </ControlTemplate>

    </Setter.Value>

    </Setter>

    </Style>

     

    <ItemsControl x:Name="procList" ItemsSource="{Binding}">

    </ItemsControl>

    Wednesday, November 29, 2006 10:49 AM
  • Yes, styling the Button helps when using a Button. Using my custom FrameworkElement-derived object still has several issues, though:


    1. I need to derive from Control instead of FrameworkElement to be able to use the template

    2. The ItemsControl still insists on calling my custom OnRender function, it seems that the control template has little effect. Of course, this could have something to do with me having to implement some stuff to get control templating to work properly for my custom control (?), I not sure.

    3. I'm now not able to add my control to another view (a Canvas), but get thrown a System.ArgumentException with message "Specified Visual is already a child of another Visual or the root of a CompositionTarget."

    Just to explain what I really want to do;  I want to add a set of custom controls to a Canvas and at the same time add a templated version of each control in a list (ItemsControl/ListBox) for the user to select. The reason that I went for the ItemsControl instead of the ListBox in the first place was that I don't want the keyboard functionality and the default selection functionality of the ListBox.

    Maybe it is more easy to template away some of the ListBox functionality that I don't want, since the ListBox otherwise works as expected, rather than trying to get my custom controls to appear as I want in an ItemsControl ?

    Regards,
    Leif O 

     

    Wednesday, November 29, 2006 1:28 PM
  • I am also having this issue.  Did you ever determine a solution? 

    I am in the same situation.  I want to use an ItemsControl to bind to a collection of UIElements, but it does not apply my data template.  If I use a ListBox, then the binding works, but I inherit the extra functionality of a ListBox.
    Tuesday, March 24, 2009 1:51 PM
  • I believe I found the answer, over here .  I'll repost the proposed solution, which seems to work fine for me :)

    ==========================================

    After using Reflector to examine the ItemsControl code, the IsItemItsOwnContainerOverride method returns true if the item is a UIElement. You can create a subclass of ItemsControl, and change this method to:

    protected
     
    override
     
    bool
     
    IsItemItsOwnContainerOverride
    (
    object
     item
    )
    
    {
       
    return ( item is ContentPresenter );
    }

    If you then use that class instead of the ItemsControl, it will work as expected, but won't have the undesired functionality of ListBox.

    ==========================================

    So this is what my inheriting class that I used instead looks like in the end:

    public class ItemsControlThatAllowsBinding : ItemsControl
    	{
    		protected override bool IsItemItsOwnContainerOverride(object item)
    		{
    			return (item is ContentPresenter);
    		}
    	}
    


    - Dan - "Can't never could do anything"
    Wednesday, November 24, 2010 11:25 PM