Updating the wpf property of the ListViewItem

I have a list tied to a ThreadSafeObservableCollection. The background of each of these elements is set to an enum which is done through a color converter, here's the code for these 2 settings.

<UserControl.Resources>
    <EncoderView:EncoderStatusToColorConverter x:Key="ColorConverter"/>
    <Style x:Key="ItemContStyle" TargetType="{x:Type ListViewItem}">
        <Setter Property="Background" Value="{Binding Converter={StaticResource ColorConverter}}" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    </Style>
</UserControl.Resources>

      

what i want is that the background color in the listviewItem will change from Red - Yellow - Green based on the enum value. Which is updated based on business logic rules. This currently works, but only for the initial display of the element. When I make changes to the "Status" property of the object that the listItemView is bound to, the background is not updated. If I remove the object from the collection, change the status and then add it to the collection again, the background is updated.
I tried making an IPropertyNotify object and throwing an event on the property changed the setter, but it didn't work.

Does anyone know if there is something special I have to do to get the background of the list item to update. I am also open to other ideas on how to solve this problem, thanks. here's the XAML for the ListView. EncoderService.Encoders is my ThreadSafeObservableCollection of Encoder objects.

        <ListView  AutomationProperties.AutomationId="FinishScreen"  
                   ItemsSource="{Binding Path=EncoderService.Encoders}" 
                   x:Name="DataListView" Grid.RowSpan="1" Grid.Row="1" Margin="5"
                   ItemContainerStyle="{StaticResource ItemContStyle}"
                   Background="Azure">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="MAC">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ContentControl Content="{Binding Path=MAC}" ToolTip="{Binding Path=MAC}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="IDF">...

      

+1


source to share


4 answers


The problem is that background binding accepts the entire Encoder object, which doesn't change unless you remove and add it. Even if the Encoder implements INotifyPropertyChanged, the binding still looks at the entire Encoder object and doesn't know which Encoder properties are relevant to your EncoderStatusToColorConverter, so it won't update itself.

The solution in your case is to narrow the scope of the background binding to only the property (or properties) related to the EncoderStatusToColorConverter. Any properties in the path of your binding will be tracked for updates. So, for example, if you only want status:



<Style x:Key="ItemContStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="Background" Value="{Binding Path=Status, Converter={StaticResource ColorConverter}}" />
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>

      

In this case, if you implement INotifyPropertyChanged on Encoder and notify when the state changes, the binding should update for you. This also means that you need to update the EncoderStatusToColorConverter, so it only accepts the state type.

+2


source


Have you tried using DataTemplateSelector? I use it to change which template is used for the ListBoxItem, which basically just changes the foreground color based on the property. I have not tried the scenario you are doing where the data changes after the page has loaded, but I donโ€™t understand why that wouldnโ€™t work.

I have this class:

public class UniqueWordDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item != null && item is WordScore)
        {
            WordScore word = item as WordScore;

            FrameworkElement elem = container as FrameworkElement;

            if (word.IsUnique)
                return
                    elem.FindResource("UniqueWordListTemplate") as DataTemplate;
            else
                return
                    elem.FindResource("WordListTemplate") as DataTemplate;
        }

        return null;
    }
}

      

In my management resources, I have this line:

    <UserControl.Resources>
    ...
    <my:UniqueWordDataTemplateSelector x:Key="myDataTemplateSelector"/>

      



I also have two of my templates:

    <DataTemplate x:Key="WordListTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="210" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Path=Word}" Background="{x:Null}" Foreground="White"/>
            <TextBlock Text="{Binding Path=Score}" Background="{x:Null}" Foreground="White"/>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="UniqueWordListTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="210" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Path=Word}" Background="{x:Null}" Foreground="Gold"/>
            <TextBlock Text="{Binding Path=Score}" Background="{x:Null}" Foreground="White"/>
        </Grid>
    </DataTemplate>

      

And then I use the following for my list:

   <ListBox x:Name="PlayerList2" ItemTemplateSelector="{DynamicResource myDataTemplateSelector}" IsSynchronizedWithCurrentItem="True" Background="#FF252525"/>

      

+1


source


I like this approach and I'm going to try to coax it, but the only problem I see right off the bat is that I'm using a GridView because I'm displaying tabular data. I like the column headings. But I think I can find a way to get around this. I'll probably just put my own column headings manually.

How does the ListItem get notified that it should update the data template? does this happen every time it receives a PropertyChanged event for any of its constrained elements?

0


source


I think I may be confused about what should affect INotifyPropertyChanged.

So, I have an ObservableCollection of "Encoder" objects. The ObservableCollection is obviously observable and when I add and remove things from it it gets updated. but all the "Encoder" properties are not updated. From what I understand, this means that the "Encoder" class has to implement INotifyPropertyChanged and send the property name in the event. Is this correct thinking? because it doesn't work at the moment. I want to make sure I have the correct theory before posting more code.

thank

0


source







All Articles