Search code examples
c#wpfitemscontrolitemtemplate

How to access newly created ItemsControl children controls?


I am creating a Map control/framework library. I have a main Map control which can contain a number of LayerControls. I planned to make those LayerControls to inherit from ItemsControl to allow user use ItemTemplate to define various objects with binding to ViewModels to appear on the map like charts, pins, ships, etc.

Here is an example usage:

<map:Map
    Scale="{Binding Path=Scale}"
    CenterLocation="{Binding Path=CenterLocation}"
    MapParametersChangedCommand="{Binding Path=MapParametersChangedCommand}"
    MouseDoubleClickCommand="{Binding Path=ChartObjectInfoRequestedCommand}"
    UseWaitCursorIcon="{Binding Path=UseWaitCursorIcon}"
    >
    <map:Map.Layers>
        <layers:GeoImageLayer ItemsSource="{Binding Path=WmsLayerViewModel.WmsMaps}">
            <layers:GeoImageLayer.ItemTemplate>
                <DataTemplate DataType="{x:Type viewModels:WmsMapViewModel}">
                    <map:GeoImage
                        Source="{Binding Path=ImageSource}"
                        ImageOffset="{Binding Path=ImageTransform}"
                        />
                </DataTemplate>
            </layers:GeoImageLayer.ItemTemplate>
        </layers:GeoImageLayer>
    </map:Map.Layers>
</map:Map>

Now my problem: When a map specific control (image, pin, ship, etc) is created from ItemTemplate I need to access it to subscribe them to some map specific events and later on to unsubscribe on their removal. I want all of this to be handled internally without the need of using ViewModels to handle it. In one of the questions asked here on SO someone suggested this solution:

protected abstract class BaseGeoLayer : ItemsControl
{    
    protected BaseGeoLayer()
    {
        ((INotifyCollectionChanged) Items).CollectionChanged += OnCollectionChanged;
    }
    
    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // doing stuff
    }
}

But CollectionChanged event gives the bound ViewModels, not the controls. Also I have to take into consideration possibility to iterate over those child controls during runtime.

Is there an easy way to achieve this without using VisualTreeHelper?


Solution

  • I managed to get the created/removed control by adding a bubbling RoutedEvent which is fired by the control's Loaded/Unloaded events.