简体   繁体   中英

WPF MVVM updated source but not updating GUI

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM