Click here to Skip to main content
15,074,987 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello,
I'm a beginner in programming, C#, WPF, everything really and I'm learning by creating an application where you can draw out a drainage network, and carry out a bunch of calculations on that network.
I'm using WPF and drawing lines and nodes on a canvas.

My initial plan was, when a node is placed on the canvas, an entry into an SQLite database is created as a convenient way to store the data, query it, and modify it at a later stage.
It's also convenient that the database can be saved and loaded making the whole file open/save element really straight forward.
I plan to also use the data in the database to redraw to the canvas in the event of a pan of zoom (not built in yet).

The problem is I also have to create an instance of the class "Node" in order to place it on the Canvas.

This would be ok, until the user wants to edit the network, which is the next bit I want to work on.

It's easy enough to find the node in the database when the user clicks in the vicinity of the node.
But then how would also also modify the class for that node shown on screen?
I could clear the canvas and redraw everything form the database but that seems very inefficient.

I assume I could create a list of all the instances of the node class, and then use LinQ to find that node instance, and modify it, but then I'm having to do the query twice which again doesn't seem very efficient.
I'm also unclear how I would access that class since they all effectively have the same name `node`.

So my questions are:
1. Should I avoid using the database and rely solely on the node class to query, modify etc?
2. Regardless of the answer to question 1, how do I modify a specific instance of "node"?

Many thanks.

What I have tried:

Here is my method to create a new node:

private void AddNode(MouseButtonEventArgs e)
        {
            Node node = new Node();
            CadCanvas.Children.Add(node.DrawNode(currentMousePoint.X, currentMousePoint.Y));
            
            database.AddNode("test", currentMousePoint.X, currentMousePoint.Y);

        }




and here is my node class that creates the graphic for the canvas:

public class Node
    {

        public int id;
        public string refernce;


        public Ellipse DrawNode(double x, double y)
        {
            Ellipse e = new Ellipse();
            e.Height = 20;
            e.Width = 20;
            e.Fill = Brushes.Blue;

            double left = x - (20 / 2);
            double top = y - (20 / 2);

            e.Margin = new Thickness(left, top, 0, 0);

            return e;

        }

    }
Posted
Updated 19-Apr-21 23:44pm
Comments
Richard MacCutchan 16-Apr-21 9:17am
   
            double left = x - (20 / 2);
            double top = y - (20 / 2);

20 divided by 2 will always result in 10. I suspect that is not the calculation you really want.
Richard!i! 16-Apr-21 10:05am
   
Hi, it is for now.
The 20 will eventually be replaced by a variable to allow the user to select different node sizes and keep the positioning in the center of the node.
Whilst I'm experimenting I find it easier to hard code such things and sort it later.
If I write 10, it might be that little bit harder for me to remember what it is in the future.
Richard MacCutchan 16-Apr-21 10:38am
   
OK.

As to your questions, I would just say that assuming the number of nodes is not such that they fill your memory it makes sense to read them in to a List<t> first. That saves you lots of database accesses; you only need it to write updated nodes.
Richard!i! 16-Apr-21 12:15pm
   
Thanks for that.
I hadn't released you could place instances of a class in a list. So in my case:
List<node> nodeList = new List<node>();
I'll have a play this weekend and see how I get on. If it works as I expect it will basically be like a database which is great.
Follow up question if I may, if I know I'm only going to need one copy of this list for the whole application and I will want to modify it and read it form multiple classes, would it be so terrible if I placed it in a static class to save creating multiple instances and referencing them all together and passing them around.
Richard MacCutchan 16-Apr-21 12:26pm
   
Instances of a class are just objects, and are not so different from fundamental types (int, char etc.), in how they may be manipulated.

You do not need to put it in a static class, and you do not need to create multiple instances, of the List. If you feel that need then something is wrong with your design.
Richard!i! 16-Apr-21 15:36pm
   
Thanks for your feedback. I'm probably going way off topic now, but the way I would avoid using a Static class to store my data would be as follows:

My nodeList lives in class Data.
It's first instantiated in MainWindow but I also want to modify it or query it in NodeListOptionsUserControl.

I may just need a key word to google to understand how to avoid creating multiple instances of Data and equating them to eachother.

public class Data
    {
        public List<Node> nodeList = new List<Node>();
    }

    public class MainWIndow
    {
        public MainWIndow()
        {
            NodeListOptionsUserControl nodeListOptionsUserControl = new NodeListOptionsUserControl(data);
        }
        Data data = new Data();
        private void addNode()
        {
            Node node = new Node();
            data.nodeList.Add(node);
        }
    }

    class NodeListOptionsUserControl
    {
        Data data = new Data();
        public NodeListOptionsUserControl(Data _data)
        {
            data = _data;
        }

        //do stuff to data here.....
    }
Richard MacCutchan 17-Apr-21 3:47am
   
You will just end up in a mess with all these different instances. You only need a single List to hold your node information. That provides the basis of all the data that is to be processed during the life of the app. the actual list can be passed between different methods in order to read, insert, update, display etc. I would suggest you research the Model-View-Controller paradigm, to see how things should be done.
Gerry Schmitz 16-Apr-21 13:59pm
   
You need to estimate your storage requirements. I have an app with "dictionaries" that have as many as 80,000 entries (hash sets), and I run them all from memory; on PC's and (8 GB) tablets; with no lag. I also have a (up to) 49 x 49 grid based game (2400+ shapes) that runs fine. UWP apps. Serialize at the start or end; or any required points (save).
Richard!i! 16-Apr-21 15:39pm
   
Hello, I can't imagine I would need more than 1000 objects and that's probably a very high estimate.
I do plan on being able to load in DXF files which could generate thousands of lines, but I believe I can write that to a bitmap.
Good to know I'm unlikely to run into major memory issues provided I design everything right. THanks.

1 solution

The proper way to approach this is with the MVVM (Model-View-ViewModel) pattern.

The model is responsible for loading and saving the data.

The viewmodel is an instance of the model that contains additional code to allow viewing/manipulation in the view.

The view uses (binds to) the viewmodel, and doesn't know anything about the model, or where the data might come from.

Honestly, the topic of MVVM is way too huge to cover in a QA answer, and you'd be much better served by searching CodeProject for articles relating to it.

My advice is to nail down the model/viewmodel interaction, and THEN worry about presenting the viewmodel in the UI. I've written a number of articles here that use MVVM in a WPF ecosystem. Those articles contain code to make your WPF MVVM live a lot simpler.
   
v2
Comments
Richard!i! 20-Apr-21 8:21am
   
Hello, thanks for your advice. I went down a bit of a reading rabbit hole this weekend and thankfully came up with a similar conclusion.
I mostly read about MVVM, SOLID and took a particular interest in the Dependency inversion, that if implemented through Dependency Injection would allow me to inject either new instances everytime I have a class that needs one, or apparently I can inject an object (I think the term was singleton) which would mean that all my viewmodels can access and modify that one instance which would help my hugely.
I've started having a little play with mvvmCross library which should handle all of the above to allow me to get going a little quicker.
Thanks again

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