0

I'm designing an MVVM WPF app, and one of the controls is like this,

<ListView Grid.Row="5"  Margin="0,5,0,0" ItemsSource="{Binding temps, Mode=TwoWay}"/>

In the ViewModel, I have

public class IndicatorLightVM:DependencyObject
{
/*---*/
    public List<DataDev> temps { get; set;}
/*---*/

    public IndicatorLightVM(IComm icomm, int moduleAddr = 1)
    {
        iComm = icomm;
        pdm = new IndicatorLight(icomm, moduleAddr);
        temps = pdm.DataDevs;
    }

DataDevs has a list of DataDev as an attribute and DataDev is

public abstract class DataDev: INotifyPropertyChanged
{
    public int ModuleAddr { get; set; }
    private double _value;
    public double Value {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
            OnPropertyChanged("Value");
        }
    }
/*---*/
}

Then I call a method updating the Value of Datadev. When I tracked into the code, Values are changed but the UI is not updating.

public override CommResults ReadData()
    {
        channelselect = DataDevs.Count(d => d.isTest);
        byte[] recvbuf = new byte[channelselect * 2+7];
        byte[] sendbuf = new byte[7];
        sendbuf[0] = Convert.ToByte(ModuleAddr % 256);
        sendbuf[1] = 0X07;
        sendbuf[2] = 0X07;
        sendbuf[3] = BoolsToBytes()[0];
        sendbuf[4] = 0X00;

        CommResults result = GetCommData(sendbuf, recvbuf, channelselect * 2+7);
        if (result != CommResults.OK)
        {
            return result;
        }          
        AnalyseData(recvbuf);
        return CommResults.OK;
    }

    private void AnalyseData(byte[] recvbuf)
    {
        for (int i = 0; i < channelselect; i++)
        {
            byte ss = Convert.ToByte(recvbuf[i * 2 + 6] & 0xF8);
            if (Convert.ToInt32(ss) == 0xF8)
            {
                DataDevs.Where(x=>x.isTest).ToArray()[i].Value = (-((256 - recvbuf[i * 2 + 6]) * 256 - recvbuf[i * 2 + 5]) * 0.0625);
            }
            else if (Convert.ToInt32(ss) == 0)
            {
                DataDevs.Where(x => x.isTest).ToArray()[i].Value = ((recvbuf[i * 2 + 6] & 7) * 256 + recvbuf[i * 2 + 5]) * 0.0625;
            }
        }
    }

Sorry for missing code.

  • `Then I call a method updating the Value of Datadev.` Where is it ? Please add the code to your question. – Blacktempel Sep 04 '17 at 06:00
  • Why does your "View-Model" derive from `DependencyObject` ? You should rather derive from an abstract base class which implements INotifyPropertyChanged. You might also want to add a notifier for your list, in case you exchange it with another list object. – Blacktempel Sep 04 '17 at 06:09
  • How does the UI access the `Value` property. I don't see `DisplayMemberPath`, so I don't know whether you just have a `ToString` override in your `/*---*/` part of code... – grek40 Sep 04 '17 at 06:11
  • 1
    It would be better if you create a [`MCVE`](https://stackoverflow.com/help/mcve). There are a lot of details missing. – Blacktempel Sep 04 '17 at 06:13
  • @grek40 yes, I override ToString – user2951219 Sep 04 '17 at 06:22

2 Answers2

4

The problem is you don't directly use the Value in your UI.

Solution:

<ListView
    Grid.Row="5"
    Margin="0,5,0,0"
    ItemsSource="{Binding temps, Mode=TwoWay}"
    DisplayMemberPath="Value"/>

Your current approach goes the following route:

Value -> ToString -> GUI

So the GUI doesn't know it has to update on Value change. WPF will only react to property change notifications when it is aware of the property being used in the GUI and that doesn't work via ToString but only with ...Path="PropertyName" or with Bindings targeting the property.

grek40
  • 13,113
  • 1
  • 24
  • 50
-1

Change the type of the List to an ObservableCollection.

public class IndicatorLightVM:DependencyObject
{
    /*---*/
    public ObservableCollection<DataDev> temps { get; set;}
    /*---*/
}

ObservableCollection - Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.

Update

You need a "custom" ObservableCollection. This question is a possible duplicate of this SO answer. To get there you still need and ObservableCollection. By implementing the answer there you'll solve your issue.

Mihail Stancescu
  • 4,088
  • 1
  • 16
  • 21
  • He's not adding or removing an element. He's modifying the content of an element which already has a notifier. – Blacktempel Sep 04 '17 at 06:07
  • I've tried ObservableCollection, still not working. I thought ObservableCollection is used when you removing/adding elements from/to a list. Yeah, I'm doing what Blacktempel said. – user2951219 Sep 04 '17 at 06:08
  • 1
    At least the accepted answer in the linked SO question doesn't really address the issue of this question. So if you think its a duplicate, you should mention which answer would specifically be the solution. – grek40 Sep 04 '17 at 06:22
  • You are correct @grek40, thank you for pointing it out. The answer that would help this question is the [second one](https://stackoverflow.com/a/5256827/3164614). Because that answer provides the way to update all the bindings. – Mihail Stancescu Sep 04 '17 at 06:26