UniformGrid and ItemsSource

8.1k views Asked by At

I have a UniformGrid. Inside, I would like to put a Grid which contains 2 children - and Image and a Canvas. I already have a List<Grid> member which contains a Grid with that definition.

I'm updating the source of the Image from null to an actual image, expecting the image to be shown inside the UniformGrid, but nothing happens.

Here's my code:

Xaml:

<Border Grid.Row="0" >
        <ItemsControl x:Name="StreamsItemsControl" ItemsSource="{Binding Streams}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid x:Name="StreamsGrid"  ClipToBounds="True" Height="300" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Border>

ViewModel:

private List<Grid> m_streams = new List<Grid>();
public List<Grid> Streams
        {
            get { return m_streams; }
            set
            {
                m_streams = value;
                OnPropertyChanged("Streams");
            }
        }

Edit: Adding more code:

    public struct StreamContainer
    {
        public string StreamName;
        public Grid StreamGrid;
        public Canvas StreamCanvas;
        public Image StreamImage;
    }
    private readonly List<StreamContainer> m_streamsContainer = new List<StreamContainer>();

    public SequencesPlayerViewModel()
    {
        RegisterStream("Color");
        RegisterStream("Depth");
        RegisterStream("Ir");
        RegisterStream("Left");
    }

    private void RegisterStream(string streamName)
    {
        StreamContainer streamContainer;

        streamContainer.StreamName = streamName;
        streamContainer.StreamCanvas = new Canvas { Name = streamName + "Canvas", Background = Brushes.Transparent, VerticalAlignment = VerticalAlignment.Top };
        streamContainer.StreamImage = new Image { Name = streamName + "Image", Stretch = Stretch.Uniform, VerticalAlignment = VerticalAlignment.Top };

        var widthBinding = new Binding { Path = new PropertyPath("ActualWidth") };
        var heightBinding = new Binding
        {
            Path = new PropertyPath("ActualHeight"),
            Source = streamContainer.StreamImage
        };


        streamContainer.StreamCanvas.SetBinding(FrameworkElement.HeightProperty, heightBinding);
        streamContainer.StreamCanvas.SetBinding(FrameworkElement.WidthProperty, widthBinding);

        streamContainer.StreamGrid = new Grid { Name = streamName + "Grid" };
        streamContainer.StreamGrid.Children.Add(streamContainer.StreamImage);
        streamContainer.StreamGrid.Children.Add(streamContainer.StreamCanvas);

        streamContainer.StreamGrid.Visibility = Visibility.Collapsed;

        m_streamsContainer.Add(streamContainer);
    }

    private void AddStream(StreamContainer currentStream)
    {
        var listOfStreams = GetListOfStream();

        if (listOfStreams.Count > 0)
        {
            var streamToAdd = listOfStreams.Find(currStream => currStream.Name == currentStream.StreamName);
            if (streamToAdd != null)
                if (!String.IsNullOrEmpty(currentStream.StreamName))
                {
                    currentStream.StreamGrid.Visibility = Visibility.Visible;
                    (currentStream.StreamGrid.Children[0] as Image).Source = streamToAdd.ImageBitmap;
                }
        }

        Streams.Add(currentStream.StreamGrid);
    }

    private void OnNewFrameReady(uint frameNumber)
    {
        try
        {
            var listOfStreams = GetListOfStream();

            foreach (var elem in Streams)
            {
                var currentCanvas = (elem.Children[1] as Canvas);
                var canvasName = currentCanvas.Name.Split(new[] { "Canvas" }, StringSplitOptions.RemoveEmptyEntries).First();

                var currentStream = listOfStreams.Find(currStream => currStream.Name == canvasName);
                if (!String.IsNullOrEmpty(currentStream.Name))
                    (elem.Children[0] as Image).Source = currentStream.ImageBitmap;
                Panel p = currentCanvas;
                elem.UpdateLayout();

                elem.Width = (elem.Children[0] as Image).ActualWidth;
                elem.Height = (elem.Children[0] as Image).ActualHeight;
                elem.UpdateLayout();
            }
        }
        catch (Exception ex)
        {
        }
    }

The ViewModel is connected correctly, and the Bindings of the other controls are working properly.

I can also see that the Streams member is updated correctly, meaning that the Image was correctly updated with the new Source.

What am I missing?

1

There are 1 answers

1
bdimag On BEST ANSWER

Perhaps the issue is that your items are not showing up at all -- not that the image isn't updating (because I see you're updating the source property of the image element directly)... With a list, the PropertyChanged event will only fire when the List<> is changed, not when something is added to it, unlike the ObservableCollection<> which fires events when items are added/removed/replaced/cleared.

Try replacing your List<> with an ObservableCollection<> (found in System.Collections.ObjectModel)

Other than that, the Grid and Image could instead be defined in a DataTemplate within the ItemsControl.ItemTemplate and the Source bound to a property of a stream ViewModel (which is what you should have a collection of) -- but unrelated to the issue.