Yorrick
Yorrick

Reputation: 377

How to properly bind a ListView so that it's items can receive a background value?

I'm currently working on a small Video Poker app, partially because it's fun & because I needed a project for school.

Unless I missed something, my logic should be done, but now, as I'm turning my attention to the UI aspect of the app, I've hit a snag.

What I need/want my ListView to do is this:

So far I've had "some" success, meaning I've been able to have it work so that I can select an item through mouse-clicks, after which the color changed, however I couldn't get it to work by changing the SelectedItem to the winning hand.

I've tried just about anything I can think of & I've hit a dead end. I'm fairly sure it's somehow achieved through Binding data, but all my efforts so far have failed. I still lack quite a bit of both knowledge & experience when it comes to Databinding XAML elements.

If anyone here could help me out with a neat/clean/efficient way to achieve this, it would be greatly appreciated.

XAML:

<ListView x:Name="lvTest" HorizontalAlignment="Left" Height="200" VerticalAlignment="Top" Width="160" Margin="10,10,0,0">
<ListView.Resources>
    <Style TargetType="GridViewColumnHeader">
        <Setter Property="Visibility" Value="Collapsed" />
    </Style>
    <Style TargetType="{x:Type ListViewItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListViewItem}">
                        <GridViewRowPresenter />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ListView.Resources>
<ListView.View>
    <GridView>
        <GridViewColumn Width="105" DisplayMemberBinding="{Binding HandNaam}"/>
        <GridViewColumn Width="45" DisplayMemberBinding="{Binding Betaling}"/>
    </GridView>
</ListView.View>
</ListView>

C#:

List<Hand> hands = new List<Hand>();
//Bet has been changed, (re-)populate the ListView
void Betchanged()
{
    hands.Clear();
    lvTest.ItemsSource = null;
    for (int i = 0; i <= 8; i++)
    {
        hands.Add(new Hand(Hand.hands[i], bet));
    }
    lvTest.ItemsSource = hands;
}

//Game ends
//After checking for a winning hand, highlight that hand in the ListView
private void EndGame()
{
    //Do some stuff

    //Check if there's a winning hand
    int winnings;
    Hand hand = null;
    winnings = Poker.FindWin(splK, hands, out hand); //out hand is of type Hand

    //If there's a winning hand, highlight it in the ListView
    if (hand != null)
    {
        foreach (Hand h in lvTest.Items)
        {
            if (h.HandName == hand.HandName)
            {
                //This seems like the most logical (maybe not most efficient) way to find the correct item in the ListView
                //Here's where the Background property for the ListViewItem should be changed
            }
        }
    }
    //Do some more stuff
}

PS: The current Template style in my XAML is what's overriding my ListViewItem's hover/click interactions.

Edit: Here's a screenshot with a possible scenario when the Background for a ListViewItem should be changed: Example scenario

Upvotes: 1

Views: 321

Answers (1)

toadflakz
toadflakz

Reputation: 7944

Your ItemsSource in order to notify the control via the Binding that it's contents have changed, needs to implement INotifyCollectionChanged. At the moment, the most common generic collection to implement this interface is ObservableCollection<T>.

hands should be an ObservableCollection<Hand> rather than a List<Hand>.

Edit based on comment:

WPF Binding works on notifications of changes. For properties, this means implementing INotifyPropertyChanged on classes that need to notify that their properties have changed. Your Hand class should implement INotifyPropertyChanged for when the specific value you want to change has changed.

Presentation logic should be handled by the View class (or code related to the View like a Converter) so you should bind to your Model property value and convert it to a Brush object using a Converter.

You could just expose a Brush on your Model object but that would be breaking MVVM pattern as a ViewModel is not supposed to have View-specific/presentation technology classes embedded in them in order to be presentation technology agnostic.

Second edit based on second comment:

Converters are code that convert values from one type to the other by implementing IValueConverter interface ( MSDN : IValueConverter documentation ). They need to be declared as resources in your XAML and referenced using StaticResource directives in the Binding.

An excellent tutorial on this (and other basic WPF subjects) can be found at WPFTutorial.com - Value Converters

Upvotes: 1

Related Questions