locked
How to Name items in an ItemsControl RRS feed

  • Question

  • Hi everyone.

    I would like to name the items inside an ItemsControl. Without a name I can't run animations on the ItemsControl items easily. The animations I want to run can't be put inside a DataTemplate.

    The SceneItems Model has a property called Name that needs to be transferred to the SceneItem ContentControl.

    <Window x:Class="Prototyping.ItemsControlWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:Prototyping"
            mc:Ignorable="d"
            Title="ItemsControlWindow" Height="300" Width="300">
        <Window.DataContext>
            <local:MainWindowViewModel/>
        </Window.DataContext>
        <Grid>
            <local:MyItemsControl ItemsSource="{Binding SceneItems}">
                <local:MyItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas/>
                    </ItemsPanelTemplate>
                </local:MyItemsControl.ItemsPanel>
            </local:MyItemsControl> 
        </Grid>
    </Window>
    And in my items control

    namespace Prototyping { class MyItemsControl : ItemsControl { protected override DependencyObject GetContainerForItemOverride() { // Would be nice to be able to name the SceneItem here

    // But how do I access the bound model

    // sceneItem.Name = SceneItemModel.Name;

    // this.RegisterName(sceneItem.Name, sceneItem); return new SceneItem(); } } }


    Friday, January 6, 2017 11:58 AM

Answers

  • By the time the GetContainerForItemOverride() method gets called there will be no SceneItem object to access because the data bindings haven't been resolved yet but you could handle the Loaded event of the ItemContainer and access cast the DataContext of the container to a SceneItem in this event handler:

    class MyItemsControl : ItemsControl
        {
            protected override DependencyObject GetContainerForItemOverride()
            {
                DependencyObject depObj = base.GetContainerForItemOverride();
                ContentPresenter cp = depObj as ContentPresenter;
                if(cp != null)
                {
                    cp.Loaded += (s, e) => 
                    {
                        SceneItem item = cp.DataContext as SceneItem;
          //do your thing with the SceneItem...
                    };
                }
    
                return depObj;
            }
        }
    


    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Marked as answer by hypodyne1 Friday, January 6, 2017 9:58 PM
    Friday, January 6, 2017 4:41 PM

All replies

  • By the time the GetContainerForItemOverride() method gets called there will be no SceneItem object to access because the data bindings haven't been resolved yet but you could handle the Loaded event of the ItemContainer and access cast the DataContext of the container to a SceneItem in this event handler:

    class MyItemsControl : ItemsControl
        {
            protected override DependencyObject GetContainerForItemOverride()
            {
                DependencyObject depObj = base.GetContainerForItemOverride();
                ContentPresenter cp = depObj as ContentPresenter;
                if(cp != null)
                {
                    cp.Loaded += (s, e) => 
                    {
                        SceneItem item = cp.DataContext as SceneItem;
          //do your thing with the SceneItem...
                    };
                }
    
                return depObj;
            }
        }
    


    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Marked as answer by hypodyne1 Friday, January 6, 2017 9:58 PM
    Friday, January 6, 2017 4:41 PM
  • Hi Magnus

    I was looking for something like a loaded event, I could use but neither My Items Control or the Content Control (Scene Item) has one.

    But seeing your code made me realize I can get the Data from the DataContext.

    Thank you.

    Here is the solution I came up with.

    namespace Prototyping.Controls
    {
        class SceneItem : ContentControl
        {
            protected override void OnInitialized(EventArgs e)
            {
                base.OnInitialized(e);
    
                SceneItemData data = this.DataContext as SceneItemData;
                if (data != null)
                {
                    Window window = UIHelper.GetParentOfType<Window>(this);
                    if (window != null)
                    {
                        this.Name = data.Name;
                        window.RegisterName(this.Name, this);
                    }
                }
            }  
        }
    }

    Friday, January 6, 2017 9:57 PM