none
How to dispaly multiple collections on the same page RRS feed

  • Question

  • Hi everyone I am just learning WPF using the MVVM model and have run into a problem trying to display more than one observerablecollection on the same page.  I am using VS2017.   Here is may XAML code:

    <Page
        x:Name="pageRoot"
        x:Class="Invaders.View.InvadersPage"
        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="using:Invaders.View"
        xmlns:viewmodel="using:Invaders.ViewModel"
        xmlns:common="using:Invaders.Common"
        SizeChanged="pageRoot_SizeChanged"
        ManipulationMode="TranslateX"
        ManipulationCompleted="pageRoot_ManipulationCompleted"
        ManipulationDelta="pageRoot_ManipulationDelta"
        Tapped= "pageRoot_Tapped"
        mc:Ignorable="d">
        <Page.Resources>
            <viewmodel:InvadersViewModel x:Name="viewModel"/>
        </Page.Resources>
        <Grid Background="#FF232222" DataContext="{StaticResource viewModel}">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="6*"/>
            </Grid.RowDefinitions>
    
            <StackPanel  HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal">
                <TextBlock Margin="10,10,5,5" Foreground="#FFCBBFBF">Score:</TextBlock>
                <TextBlock  Margin="5,10,10,5" Text="{Binding Score }" Foreground="#FFCBBFBF"/>
                <GridView  ItemsSource="{Binding Lives}">
                    <GridView.ItemTemplate>
                        <DataTemplate>
                            <Image Source="ms-appx:///Assets/player.png" Stretch="Fill" Height="15" Width="20" />
                        </DataTemplate>
                    </GridView.ItemTemplate>
                </GridView>
            </StackPanel>
    
            <Border Grid.Row="1" x:Name="playArea" BorderBrush="Blue" BorderThickness="2" CornerRadius="10" Background="Black" Margin="5" Loaded="playArea_Loaded">
                <ItemsControl ItemsSource="{Binding Path=Sprites}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </Border>
        </Grid>
    </Page>
    The above code produces the error message "ArgumentException: Value does not fall within the expected range."  which doesn't tell me much.   

    Now, if I remove either the GRIDVIEW block of code or the ITEMSCONTROL block of code, the error goes away and the program runs correctly (minus the removed collection).    Furthermore, if I change the Bindings to either of theses blocks of code to a bogus property the error message goes away and the program runs correctly (minus the collection data where the bogus property name was entered).  In other words, the code works fine as long as I am not trying to bind to two collections at the same time.  

    I cant figure out how to bind two different collections to two different controls on the same page.  HELP!

    • Moved by Bob Ding Monday, November 13, 2017 2:31 AM
    Thursday, November 9, 2017 5:42 PM

All replies

  • Ok lets start from the beginning. 

    1.  Here is a sample of a ListView XAML:

                                        <ListView x:Name="PART_theListView" Grid.Column="2" ItemsSource="{Binding fileList}">
                                            <ListView.View>
                                                <GridView ColumnHeaderTemplate="{StaticResource GridViewHeaderStyle}">
                                                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"></GridViewColumn>
                                                    <GridViewColumn Header="Size" DisplayMemberBinding="{Binding Length}"></GridViewColumn>
                                                    <GridViewColumn Header="Last Accessed" DisplayMemberBinding="{Binding LastAccessTime}"></GridViewColumn>
                                                    <GridViewColumn Header="Type" DisplayMemberBinding="{Binding Converter={StaticResource gets}}"></GridViewColumn>
                                                </GridView>
                                            </ListView.View>
                                        </ListView>

    A GridView is a component used in a ListView, not by itself.

    2.  Don't use ItemsControl as it is really just the base class used by controls that have better capabilities such as a ListBox.

    3.  Using a canvas as the ItemsPanel is generally not a good idea as unless you have positioning properties all items will show in the top left corner of the canvas.

    To show mulitple collections on a page all you need are mulitple ItemsControls (see above) each with their own collection property in your viewmodel.


    Lloyd Sheen


    • Edited by sqlguy Thursday, November 9, 2017 8:15 PM
    • Proposed as answer by Bob Ding Friday, November 10, 2017 8:06 AM
    Thursday, November 9, 2017 8:13 PM
  • Thanks for responding Lloyd and I appreciate where you are coming from but I am using ItemsControl to house a Canvas which is constantly  being updated with different Sprites from an observable collection in the ViewModel--the Sprites are constantly changing position on the Canvas.  The GridView is being used to house the contents of different observable collection of sprites(Lives) that is in the same ViewModel.  Although I could write code to dynamically update the Lives collection on the canvas  it just seems to be more efficient to use a control to list the contents.  As I am so green at this, I hope that my logic makes sense and that I am communicating my issue correctly.
    Thursday, November 9, 2017 9:09 PM
  • BTW I'm retired as well.

    There is no benefit to using an ItemsControl.  It has very little sizing capabilities ,no selection capability.  Whatever you think you will gain by using it as opposed to a ListBox you will eventually find that you will change it .

    Using a Canvas brings a whole new set of problems.  Each of your sprites in the collection will be presented within an ItemContainer.  You have to come up with some way of positioning these ItemContainers.  To do this you will need properties to indicate the top and left positions of the sprite (which is actually the ItemContainer).

    You will then need to style the ItemContainer so that it will respond to the properties mentioned above.  

    Sample of what I'm talking about:

            <Style TargetType="ListBoxItem">
                <Setter Property="Canvas.Left" Value="{Binding theLeft,FallbackValue=0}"></Setter>
                <Setter Property="Canvas.Top" Value="{Binding theTop,FallbackValue=0}"></Setter>
            </Style>
    

    And the ListBox:

            <ListBox Grid.Row="1" ItemsSource="{Binding theList}" Background="Transparent">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid VerticalAlignment="Top" HorizontalAlignment="Left" Width="30" Height="30" PreviewMouseDown="Grid_PreviewMouseDown">
                            <Path Data="M127,37L104,105 34,105 91,150 69,218 127,176 187,218 164,150 223,105 151,105 127,37" StrokeThickness="5" 
                              Fill="{Binding theColour}"  Stretch="Fill" >
                            </Path>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas></Canvas>
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
            </ListBox>
    


    Lloyd Sheen

    Thursday, November 9, 2017 9:30 PM
  • Hi,

    I totally agree with Lloyd, there are a lot dubious place in the code you show.

    WPF does not have a GridView control, so you can not add GridView in stackpanel .

    You can use  GridView as view of ListView , you can set the View property of a ListView to GridView mode. A GridView is used for arranging data in columns and adding layout and design support to a ListView.

    I suspect you can get good results if you use a canvas to override the ItemsControl.ItemsPanel template.

    If you describe the overall requirement completely then we can give good specific advice.

    Sincerely,

    Bob



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, November 10, 2017 8:13 AM
  • I generally agree with Lloyd.

    Why am I posting?

    Don't immediately dismiss itemscontrol.

    Listbox adds selecteditem and sliders.

    If you need neither, or they add more work somehow then an itemscontrol is worth considering.

    The question title doesn't really match your problem.

    .

    Just in case someone else finds this thread via it's title.

    If you wanted to bind multiple observablecollections to the one thing then you could consider a composite collection or combine their data in one ObservableCollection<object> in the viewmodel and bind to that.  So long as the things you put in a collection are reference types then you can add the same object to numerous collections.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Friday, November 10, 2017 12:26 PM
  • Opps,  While reviewing the responses something wasn't quite lining up for me and what I was trying to do and then I realized that I am using UWP not WPF to build my app. So I placed my question in the wrong category.  

    So I will repost under the proper category.  I truly apologize for the mistake and thank each of those who took the time to respond. 

    Because I intend to port what I am doing over to WPF after I get it working in UWP (for the sake of learning the differences between the two) the responses were not a total waste of time.

    Again, please accept my apologies. 

    Friday, November 10, 2017 3:19 PM
  • Yep, 25 years USAF, Command and Control, and another 10 years working as a network engineer for a major defense contractor.  Now I simply try to keep my wits about me by learning something new.

    Lloyd, I made a mistake in my posting this should be under UWP not WPF.  Sorry if I wasted any of your time.

    Friday, November 10, 2017 3:23 PM
  • Hi JustLearningWPF,

    Since you use UWP not WPF, and you posted your question again on the UWP forum at link below. So I moved your thread to off-topic forum.

    https://social.msdn.microsoft.com/Forums/windowsapps/en-US/9f422ffa-12b0-4b10-b5da-05d6546cc765/how-to-dispaly-multiple-collections-on-the-same-page?forum=wpdevelop

    Just to remind, Please consider which forum you're going to post in before posting, otherwise, the efforts of others to be useless.

    Your understanding and cooperation will be grateful.

    Sincerely,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, November 13, 2017 1:46 AM