Click here to Skip to main content
15,868,440 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
My name is Tom and I am a WPF newbie. There. I've said it. In my application, I have a WPF ListView control bound to a Dictionary of custom objects whose values change based on events occurring with equipment that I am monitoring. I would like to control the colors (background and foreground) of the ListView's contents, ideally each cell but I'll settle for the entire row, changing them to correspond to the values of a bound item's properties. I have built a Value Converter that works beautifully -- when the ListView is first bound to a new set of data. It does not get called when the bound item changes values even though the ListView does display the new data values. Some of the XAML relating to the Value Converter follows:

XML
<Window.Resources>
    <local:PickListItemBackgroundConverter x:Key="BkgConverter" />
    <Style x:Key="ICStyle" TargetType="{x:Type ListViewItem}">
        <Setter Property="Background" Value="{Binding Converter={StaticResource BkgConverter}}" />
    </Style>
</Window.Resources>
<Grid>
    <TabControl Margin="12,12,12,134" Name="tabMain" SelectionChanged="tabMain_SelectionChanged">
        <TabItem Header="Pick List" Name="tabPickList">
            <ListView Height="380" Name="lvwPickList" Width="840" HorizontalContentAlignment="Center"
                      ItemContainerStyle="{StaticResource ICStyle}" >
                <ListView.View>


What must I do to get the equivalent of the Value Converter to be called when the values of one of the bound objects change?

Update (Copied from his answer):
Thanks for the response.
I have a breakpoint inside the converter. It gets hit once for each item when the ListView is first bound; it does not get hit when the data value of a bound object changes even though the ListView does display the new value. I don't see binding errors in the output window. This behavior is not what I expected.


Regards,
Tom

Update 2 (Comment from Venkatesh's answer):

Thank you very much for taking the time to answer. I was surprised when, with no additional effort, the ListView cell contents were being updated updated to reflect the change in value.

Is that happening independently of the INotifyPropertyChanged interface implementation?

I have read through the article you reference once and I aplogize in advance if my next questions betray my lack of WPF understanding. The only ListView binding I specify in the XAML is that for the columns:

<ListView Height="380" Name="lvwPickList" Width="840" HorizontalContentAlignment="Center" ItemContainerStyle="{StaticResource ICStyle}" > 
<ListView.View> </ListView.View> 
</ListView> 


What is the default binding Mode?
Where should I specify that I want OneWay binding?
If I implement the INotifyPropertyChanged interface, will the value converter I created for setting the background color be called when a value changes or do I need to implement another converter?

Thanks in advance for your help.
Tom

Update 3 (Given the source):
OK. Here's the link. Thanks very much for taking the time to look at it.

https://cid-ecf0057ed7459dbc.skydrive.live.com/redir.aspx?resid=ECF0057ED7459DBC!104[^]

Regards, Tom
Posted
Updated 16-Feb-11 16:18pm
v4
Comments
Venkatesh Mookkan 15-Feb-11 23:52pm    
Place a breakpoint in the converter. See whether it is coming inside it. You can also check the Output Window for Binding errors. I guess like the binding is the problem.
Venkatesh Mookkan 16-Feb-11 5:08am    
Your comments should be added as replies to the actual thread. You should not add Answer unless it is an answer.
tpwright4423 16-Feb-11 8:40am    
Thanks. My "newbie" status is showing -- I blindly followed the link in the e-mail notification of your posting. :-)

You need to implement INotifyPropertyChanged interface to your data object. WPF data binding power is mainly depends on the Notify Properties. If your data class doesn't have implemented it, it will not work as you said.

You will get better idea if you read through this WPF: A Beginner's Guide - Part 5 of n[^]

Update 1:

tpwright4423 wrote:
Is that happening independently of the INotifyPropertyChanged interface implementation?

Yes.

tpwright4423 wrote:
What is the default binding Mode?

Default binding mode depends on the Property/object to which you are binding


tpwright4423 wrote:
If I implement the INotifyPropertyChanged interface, will the value converter I created for setting the background color be called when a value changes or do I need to implement another converter?

Just implement the INotifyPropertyChanged interface. The current Converter is more than enough.

Update 2 (from the source code):
I have found the issue. And fixed it using IMultiValueConverter.

Your Code:

tpwright4423 wrote:
XML
<style x:key="ICStyle" targettype="{x:Type ListViewItem}" xmlns:x="#unknown">
<setter property="Background" value="{Binding Converter={StaticResource BkgConverter}}" />
</style>


Here the binding will send the whole object (PickListItem) to the Convert function. Since it is object with will not notify as the change you done is on the properties. You are supposed to bind with Path. This is how you do.

XML
<Style x:Key="ICStyle" TargetType="{x:Type ListViewItem}">
            <Setter Property="Background">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource BkgConverter}">
                        <Binding Path="QtyPicked" />
                        <Binding Path="QtyToPick" />
                    </MultiBinding>
                </Setter.Value>
            </Setter>
        </Style>


Since it is using MultiBinding you have to change your converter to IMultiValueConverter like this,

C#
public class PickListItemBackgroundConverter : IMultiValueConverter
    {
        #region IMultiValueConverter Members
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (targetType != typeof(Brush))
            {
                throw new InvalidOperationException("The targetType must be a Brush object");
            }
            if (values.Length < 2)
            {
                throw new ArgumentOutOfRangeException();
            }
            int qtyPicked = 0;
            int qtyToPick = 0;
            int.TryParse(values[0].ToString(), out qtyPicked);
            int.TryParse(values[1].ToString(), out qtyToPick);
            Brush bBrush = Brushes.Transparent;
            if (qtyPicked > 0)
            {
                bBrush = (qtyPicked < qtyToPick) ? Brushes.Yellow : bBrush = Brushes.LimeGreen;
            }
            return bBrush;
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
        #endregion
    }


And you are done. :thumbsup:

Mark it as answer if it is helpful.
 
Share this answer
 
v3
Comments
tpwright4423 16-Feb-11 8:50am    
Thank you very much for taking the time to answer.

I was surprised when, with no additional effort, the ListView cell contents were being updated updated to reflect the change in value. Is that happening independently of the INotifyPropertyChanged interface implementation?

I have read through the article you reference once and I aplogize in advance if my next questions betray my lack of WPF understanding. The only ListView binding I specify in the XAML is that for the columns:

<ListView Height="380" Name="lvwPickList" Width="840" HorizontalContentAlignment="Center"
ItemContainerStyle="{StaticResource ICStyle}" >
<ListView.View>
<gridview>
<gridviewcolumn width="30" header="Bay"
="" displaymemberbinding="{Binding BayNumber}">
<gridviewcolumn width="35" header="Shelf"
="" displaymemberbinding="{Binding Shelf}">
<gridviewcolumn width="50" header="Position"
="" displaymemberbinding="{Binding Position}">
<gridviewcolumn width="90" header="SKU"
="" displaymemberbinding="{Binding SKU}">
<gridviewcolumn width="75" header="Qty To Pick"
="" displaymemberbinding="{Binding QtyToPick}">
<gridviewcolumn width="75" header="Qty Picked"
="" displaymemberbinding="{Binding QtyPicked}">
<gridviewcolumn width="75" header="Complete At"
="" displaymemberbinding="{Binding FormattedPickCompleteAt}">

</ListView.View>
</ListView>

What is the default binding Mode? Where should I specify that I want OneWay binding? If I implement the INotifyPropertyChanged interface, will the value converter I created for setting the background color be called when a value changes or do I need to implement another converter?

Thanks in advance for your help.
Tom
Venkatesh Mookkan 16-Feb-11 9:08am    
The answer has been updated. Let me know if you have questions.
tpwright4423 16-Feb-11 8:52am    
Well, I'm not sure why the XAML for the ListView.View didn't appear. I will try again.

<ListView Height="380" Name="lvwPickList" Width="840" HorizontalContentAlignment="Center"
ItemContainerStyle="{StaticResource ICStyle}" >
<ListView.View>
<gridview>
<gridviewcolumn width="30" header="Bay"
="" displaymemberbinding="{Binding BayNumber}">
<gridviewcolumn width="35" header="Shelf"
="" displaymemberbinding="{Binding Shelf}">
<gridviewcolumn width="50" header="Position"
="" displaymemberbinding="{Binding Position}">
<gridviewcolumn width="90" header="SKU"
="" displaymemberbinding="{Binding SKU}">
<gridviewcolumn width="75" header="Qty To Pick"
="" displaymemberbinding="{Binding QtyToPick}">
<gridviewcolumn width="75" header="Qty Picked"
="" displaymemberbinding="{Binding QtyPicked}">
<gridviewcolumn width="75" header="Complete At"
="" displaymemberbinding="{Binding FormattedPickCompleteAt}">

</ListView.View>
</ListView>
tpwright4423 16-Feb-11 8:53am    
Sigh. I will try again later -- got to run now.
tpwright4423 16-Feb-11 12:19pm    
Well, it turns out that I had previously implemented INotifyPropertyChanged in my data object for each property that can change value after it has been bound to the ListView, so raising that event whenever the property value changes is NOT causing my data converter to be called again. Got another idea?

Thanks,
Tom
 
Share this answer
 
Comments
Venkatesh Mookkan 16-Feb-11 5:09am    
I am afraid that he didn't meant that.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900