0
votes

I'm trying to add a tag to my ListView Item (like adding a tag to a button).

My XAML:

        <ListView x:Name="gamesList" IsItemClickEnabled="True" ItemClick="gamesList_ItemClick">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate>
                                <ContentPresenter/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <Grid Height="200" Width="896">
                            <Rectangle Fill="#FFCCCCCC" HorizontalAlignment="Left" Height="64" Margin="10,71,0,0" Stroke="#FFCCCCCC" VerticalAlignment="Top" Width="100"/>
                            <TextBlock x:Name="voteCount" HorizontalAlignment="Left" Margin="50,79,0,0" TextWrapping="Wrap" Text="{Binding Votes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Foreground="#FF107C10" FontWeight="Bold"/>
                            <TextBlock x:Name="voteCountText" HorizontalAlignment="Left" Margin="37,104,0,0" TextWrapping="Wrap" Text="votes" VerticalAlignment="Top" Foreground="#FF292C33"/>
                            <Button x:Name="voteButton" Tag="{Binding Slug, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Content="{Binding BtnVoted, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,143,0,0" VerticalAlignment="Top" Width="100" Background="#FF888888" Foreground="#FF292C33" Click="voteButton_Click" IsEnabled="{Binding BtnEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                            <TextBlock x:Name="voteTitle" HorizontalAlignment="Left" Margin="144,80,0,0" TextWrapping="Wrap" Text="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" FontSize="22" Foreground="#FF292C33"/>
                            <TextBlock x:Name="voteError" HorizontalAlignment="Left" Margin="144,115,0,0" TextWrapping="Wrap" Text="You already voted for this game" VerticalAlignment="Top" Visibility="{Binding Voted, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                            <Rectangle Fill="Black" HorizontalAlignment="Left" Height="4" Margin="10,180,0,0" Stroke="#FFCCCCCC" VerticalAlignment="Top" Width="801"/>
                        </Grid>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

C# (Partially):

        public async void OnLoaded(object sender, RoutedEventArgs e)
        {
            var response = await start();

            dynamic dynJson = JsonConvert.DeserializeObject(response);

            foreach (var item in dynJson)
            {
                Object votedGame = localSettings.Values[item.slug.ToString()];
                string voted = "Collapsed";
                string btnVoted = "VOTE";
                bool btnEnabled = true;

                if(votedGame != null)
                {
                    voted = "Visible";
                    btnVoted = "VOTED!";
                    btnEnabled = false;
                }

                listofGames.Add(new Games { Title = item.name, Votes = item.votes, Slug = item.slug, Voted = voted, BtnVoted = btnVoted, BtnEnabled = btnEnabled });
            }

            gamesList.ItemsSource = listofGames;
        }

        public class Games
        {
            public string Title { get; set; }
            public string Slug { get; set; }
            public string Voted { get; set; }
            public string BtnVoted { get; set; }
            public bool BtnEnabled { get; set; }
            public int Votes { get; set; }
        }

The tag should contain data about (in this case) a game title.

So, when the user clicks the item a click function should handle the event and I need to be able to get the data from the tag.

1
How do you "add a tag to a button"? Are you talking about the Tag property? Don't do that, use MVVM. Also, a little off topic -- can you explain your ItemContainerStyle?15ee8f99-57ff-4f92-890c-b56153
How are you populating the ListView? If the tutorial didn't tell you to bind an ObservableCollection to ListView.ItemsSource, it's a bad tutorial and you should find another.15ee8f99-57ff-4f92-890c-b56153
@EdPlunkett Updated the post with some of the C#Chris
It's a bit of a mess in here. Tag={Binding whatevs, Mode=TwoWay suggests you're lacking a lot of knowledge here. Might want to invest in a couple books on the subject and do some reading.user1228
Do a deep dive into MVVM. Once you get past the initial shock, things like this become trivial to code. Good luck!user1228

1 Answers

3
votes

You don't need a tag. In XAML, collection controls like ListView select the actual class instance you gave them. They try to avoid making you deal with ListViewItems in your code as much as possible. So e.ClickedItem in your event handler won't be the ListViewItem; it'll be your item, one of the Games instances you provided to ListView.ItemsSource in your List<Games>. No need to mess with Tag like in Grandpa's day.

private void listView_ItemClick(object sender, ItemClickEventArgs e)
{
    //var lv = sender as ListView;
    Games clickedGames = e.ClickedItem as Games;

    //  Do stuff with the clicked item. 
}

By the way, it looks from your code as if listofGames is a private field. That's not a good idea. Since it's not ObservableCollection, anything additions to or removals from that list won't be reflected in the ListView, so the List should really be local to the OnLoaded method, to prevent that from happening. Or better yet, change its type to ObservableCollection<Games>. That'll be a drop-in replacement for List<T>.

As I've said, I think you unfortunately stumbled on a very bad tutorial.

The "Correct" way to do this (and it really is, in practice) is to have a viewmodel which has your Games collection as a public property, and a public Games SelectedGame property as well. Then you'd bind those to ItemsSource and SelectedItem on the ListView, respectively. No ItemClicked handler. But I hesitate to urge you too strongly to drop what you're doing and start over.