New to MVVM WPF, getting data from external source

1.1k Views Asked by At

I'm new to MVVM, and I'm a bit in over my head here. English is not my preferred language, so please bear with me.

I'm trying to make a HMI for PLC. I'm supposed to connect to two different PLC, and present data from different datablocks in the PLCs. For simplicity let's talk about connecting only to one PLC, and getting data from only one datablock. The datablock has a repeating struct of data, in my solution I make each struct into a object.

For communications with the PLC I use Libnodave. MVVM Light for MVVM-thingies.

Model.

Contains the “recipe” for the PLCs struct. It also includes get-set-methods.

int _startByte;
string _name;
int _value1;
bool value2;

ViewModel.

Iherits from ViewModelBase, and has a Model-object as member. Public get-set-methods, wich raises propertychanged on set. Examples:

Public ViewModel(string name, int startByte)
{
        _model = new Model{Name = name, StartByte = startByte};
}


public int Value
{
        get{return _model.Value;}
        set
        {
                if(_model.Value!=value)
                {
                        _model.Value=value;
                        RaisePropertyChanged("Value");
                }
        }
}

CollectionViewModel.

ObservableCollection of ViewModels. Gets Models name and startbyte from ModelData.cs (a class with two arrays, name and startbyte). Using RelayCommands I've tested adding ViewModels to collection.

View.

Works for now, and will hopefully work later as well

My programs looks somewhat like this:

View
CollectionViewModel
ViewModel    ModelData
Model

(ViewModel and ModelData don't know each other)

So, over to collecting data. My plan was to let the ViewModel have a reference to a PLC-object (this is where Libnodave comes in), and using the PLC-objects methods collect data. The PLC-object represents a connection to a PLC, and contains methods for writing and reading data. In the ViewModel, I would use the PLC-objects methods to collect data (and write data).

This means a lot of PLC-references, but locking will hopefully prevent crash. My problem is I can't figure out how to give the ViewModel a reference to a PLC-object. The PLC-object will also be used by other ViewModels, and there will be two different PLS-object, one for each PLC.

Is this a valid approach, or should I look in to something completely different?

2

There are 2 best solutions below

0
On

If I'm understanding correctly, you have a PLC, with an array of data structures within it, and each of these data structures is going to be represented in your program by an object. Now multiply that by two since you have two PLCs.

For the sake of this post, let's call the class that represents one PLC PLC. Let's call each object that represents a single structure in that PLC PLCData.

Create a singleton class (or static class) that contains an array that holds your two PLC objects. Each PLC object has an array (or List<> or ...) of PLCData objects.

Now, your viewmodels just need to get hold of the instance of the singleton or static class, which is easy to do.

If you're using multithreading (using one thread per PLC to collect the data), BlockingCollection might be a good choice as a data structure for your objects.

0
On

I Think the TS is looking for a solution how to query his PLCs. If you ask me you are looking for a Repository pattern. This is a good way to get all your data. That can be reused in differenct ViewModels or other places.

The methods in your Repository will return an instance of the (Data)model of your PLC data

So you have a class named PlcRepository with an method GetData(object plcId) where you can replace the object with something usefull that will identify which Plc you're trying to query. This does all the logic to get your data from the PLC and will return the object from you Libnodave library/api

public class PlcRepository : SomeBase
{
    public PlcRepository()
    {
        //Do what you need to do
    }

    /// <summary>
    /// Query the data from your PLC
    /// </summary>
    /// <param name="plcId">The ID of the PLC to query</param>
    /// <returns>PlcData</returns>
    public PlcData GetData(object plcId)
    {
        PlcData data = new PlcData()

        //create instance of your class that is able to talk to the PLC

        //Query your plc

        //Fill your dataobject

        //return the dataobject you just filled
        return data;
    }
}

public class MainViewModel
{
    private readonly PlcRepository _plcRepository;

    public MainViewModel()
    {
        // Create instance of your Repository
        _plcRepository = new PlcRepository();

        // Get the Data from the PLC Repository and fill your property
        PlcData = _plcRepository.GetData(12345);
    }

    public PlcData PlcData { get; set; }
}