In brief
I'm after suggestions for how best to write a .NET application that provides a design canvas that will allow a user to create an object graph.
In more detail
Imagine the following .NET POCO class
public class BuildingBlock
{
public string Name { get; set; }
public BuildingBlock? Child { get; set; }
}
You can see that someone ccould create an object graph in the following manner:
BuildingBlock start = new()
{
Name = "One",
Child = new()
{
Name = "Two",
Child = new()
{
Name = "Three"
}
}
};
But, my user is not a programmer. They need to create this, but want a nice UI where they can drag 'n' drop objects, or right-click on the screen and pick "new block" etc. For those familiar with it, it would be similar to the design canvass in the Power Virtual Agents (PVA), or the designer in SQL Server Management Studio (SSMS).
I'd of course need to validate the model - so the Name property may have rules around it, such as it must be no longer than 5 characters, and can't contain numbers (simple for a Regex test). I may have a rule that the object graph can only be 12 objects "deep".
This program could save a serialized version of the object graph (xml, json etc). So also, it could read in this serialized file and paint a representation on the canvas for further editing.
Obviously my actual class would be far more complex than the one shown, but you hopefully get the gist.
What would be the best way to approach this, from a .NET perspective? I'm not sure which libraries etc I should look at. This could be a desktop app, or web/blazor.
Look up a tutorial on WinForms TreeView control which supports drag and drop, and context menus. What you will learn will be translatable to other UIs. As Henk mentioned, you need a collection of child nodes List<BuildingBlock> Children, not just a single BuildingBlock? Child.
If you want to record this in a relational database, each node will need to record a reference to its parent, e.g. Guid? ParentId.
Related
I'm planing to create an application to sort and view photos and images I have.
I want to give the program a list of folders (with subfolders) to handle and tag images with multiple, custom tags as I go through them. If I then enter one, or multiple, tags in a search bar I want all images with that tag to appear in a panel.
The go to approach would be SQL, but I don't want to have a SQL server running in the background. I want the program to be fully portable, so just the exe and maybe a small amount of files it creates.
I thought I would create a tree where every node is a folder and the leafs are the images. I would then add the tags of the leafs to the parent-node and cascade that upwards, so that the root node has a list of all the tags. This should allow for a fast search and with parallelisation for a fast building of the tree.
But before I start to work on such a tree I wondered if there is already something like this, or if there is a better approach?
Just to make it clear, I'm talking about multiple tags here, so a Dictionary won't work.
Tags by definition are unique and so cry out to be indexed and sorted.
A Dictionary<Tag,ImageCollection>. Why not? Seems ideal for tags.
A Dictionary<Image, TagCollection>. The reverse reference of the above. You don't want to try going through dictionary values to get at keys.
Create custom classes. Tag, Image, TagCollection, ImageCollection; then override Equals, GetHashCode, implement IComparable. This will optimize the built-in .net indexing, sorting, searching. Many collection "Find" methods take delegates for customized searching. Be sure to read MSDN documentation.
I think this could constitute the core structure. For any given query, staring with initial fetches from these structures should be pretty quick. And yielding custom collections will help too.
There is nothing wrong with a mix of LINQ and "traditional" coding. I expect that in any case you're better off with indexed/sorted tags.
Here's how I'd handle it.
First, use SQLite. It's a single-dll distribution, lightweight, superfast and impressively capable database whose sole purpose is to be used by these types of applications. A database is a far better approach than trying to persist trees to files (the issue with a custom persistence isn't that the idea in itself is bad, but rather than there's a dozen edge cases it'll need to handle that you're not likely to have thought of where a database has them automatically covered).
Second, set up some POCOs for your media and your tags. Something like this:
abstract class Media
{
public string Filename {get;set;}
public virtual ICollection<Tag> Tags {get;set;}
}
public class Image : Media
{
public ImageFormat Format {get;set;}
public int ResX {get;set;}
public int ResY {get;set;} // or whatever
}
public class Video : Media
{
public VideoFormat Format {get;set;}
public int Bitrate {get;set;}
}
public class Tag
{
public string Name {get;set;}
public virtual ICollection<Media> Media {get;set;}
}
This forms the basis for all of your MVVM stuff (you're using MVVM with WPF, right?)
Use Entity Framework for your data access (persistence and querying).
With that, you can do something like this to query your items:
public IEnumerable<Media> SearchByTags(List<Tag> tags) {
var q = from m in _context.Media
join mt in _context.MediaTags on m.ID = mt.ID
join t in tags on mt.Name = tag.Name
select m;
return q;
}
That will covert to a relatively optimized database query and get you a list of applicable media based on your tags that you want to search by. Feed this list back to your presentation (MVVM) layer and build your tree from the results.
(this assumes that you have a table of Media, a table of Tags, and a junction/bridge table of MediaTags - I've left many details out and this is very much aircode, but as a general concept, I think it works just fine).
Before everyone throws stones at me, I have searched Google / MSDN / StackOver flow for related questions and answers but none of them suited my needs.
I'm working on a rather large application in C# - Windows Forms that is currently divided into the following:
Data-Layer
Domain-Layer
UI-Layer
Basically in my current situation the roles of this layers are the following
The Data-Layer's responsability is to communicate with the data-store, basically CRUD operations.
The Domain-Layer's responsability is to hold the model of our objects, create the objects, apply business-rules etc.
The UI-Layer, well, basically this is what the user sees and interacts with.
My problem is the following:
From the UI Layer the user has access to fields like: Name, Project Name, Project Number which basically are TextBoxes, Calendars etc - all of them are UI Components.
After the input of the user I call a method named: AddExplorerNode(string name, string projectName, int projectNumber) which resides in the Domain-Layer. This method is responsible based on the passed parameters to create an ExplorerNode Object ( a "special" TreeNode ) which requires the passed parameters to actually be valid.
After the object has been created, sanitized, validated etc - the same method mentioned above passes the created object to the Data-Layer which pushes it to a Cache-Repository and then to persists it to the data-store if everything went OK in the Cache.
So until now, basically everything is separated UI -> Domain -> DataLayer.
My question is, could I replace the signature of the Domain method from
AddExplorerNode(string name, string projectName, int projectNumber) to AddExplorerNode(TreeNode node) and based on the TreeNode object and its properties, construct the actual object I need ? I'm asking this because, if the Domain-Layers knows about the UI ( in this case the TreeNode UI Component ) basically we break the separation.
For example, if next year we swap WindowsForms to a Console Application, then the project is broken due to the fact that a Console Application will not have a TreeNode UI Component.
In this case, is it better to have a domain method which takes for example 5-10 parameters ( int's, strings, etc ) and based on those parameters to create my object or to replaces the parameters with a TreeNode UI Component which ?
Thank you in advance.
#EDIT:
I am asking this question, because a colleague of mine reviewed my code and started to refactor it. By refactoring he was exposing the actual TreeNode UI Component to the Domain-Layer. My approach was AddExplorerNode(string name, string projectName, int projectNumber) etc.
You can make your own class that acts in a similar way to TreeNode without actually being a TreeNode.
class TreeNodeModel
{
public string Name { get; set; }
public string ProjectName { get; set; }
public int ProjectNumber { get; set; }
}
Then you can write a method in the UI to map (copy) TreeNodeModel to an actual TreeNode.
I'm currently working on a WPF-application (C#, using the Prism framework) that will contain a drawing pane where a user can draw polygons using his mouse.
But I'm wondering how I can make these drawings persistent.
I'm guessing that the best object to contain those drawings are the Polygon object?
I would also like to have those Polygons have certain attributes, such as a color etc. (if need be I can do this by defining my own Polygon-inherited object).
But I'm especially wondering how I can make this kind of information persistent in a database? (I'm using SQLite at the moment).
I want to be able to store Polygon information, including information such as the fill-color of that Polygon etc. in a database.
I've been googling this, but I'm not finding something useful. Could someone point me in the right direction?
Thanks for any help!
You have to create model classes in order to store the necessary information, which you would like to store.
I think it might be the best solution to use Entity Framework, so you wouldn't have to bother with creating the model classes, you could use the existing ones. But, in your case, it might saves a lot of unnecessary information into your tables.
If you are creating your own model classes, you can add a helper Extension Method to .net types, such as Polygon. That method would generate a storable model class from the .net class, which can be saved to database.
For example:
Model class:
public class PolygonDbFormat // the class which contains the information you want to store
{
public string Name { get; set; }
public Brush Fill { get; set; }
}
Defining the extension method:
public static class PolygonEx
{
public static PolygonDbFormat AsDbFormat(this Polygon polygon)
{
return new PolygonDbFormat
{
Name = polygon.Name,
Fill = polygon.Fill
};
}
}
Then you can save the Polygon class to the database this way:
var dbFormat = yourPolygon.AsDbFormat();
_yourDbManager.AddEntry(dbFormat); // your implementation to store the data in database
If I have an aggregate root which consists of say:
class Parent
{
IEnumerable<Child> Children{ get; set; }
}
Children could contain any number of possible Child objects which are stored in the database.
What would be the best way of getting a total list of all Child objects to the application, so they can be presented in a UI allowing a user to attach/remove them from the Parent object?
Having a method in Parent such as
class Parent
{
IEnumerable<Children> GetAllChildObjects { get; set; }
}
would surely corrupt the model with implementation details?
Would it be ok to have a domain service which calls the Parent repository and retrieves a full list. The facade to the application could then call the service directly, ensuring the Parent model stays "pure".
Update:
To give a bit more detail, i'm tidying up a system and trying to give it some structure.
A User can hold a number of WorkLocations. WorkLocations are pretty simple. The current system contains a webpage which displays user details including a full list of valid WorkLocations. Selecting locations from the list updates the User model with the new locations.
Currently, the UI pretty much hits the DB and pulls out the full list of WorkLocations. I need to pull this back into a more structured form.
Or, does this suggest that WorkLocation should not be in the User root as it currently is?
Am I correct in thinking that you want all the WorkLocations from the database, regardless of what User they are attached to (if any)?
If so I would definitely go for the service approach, something like:
public interface IWorkLocationsService
{
IEnumerable<WorkLocation> GetAllWorkLocations();
}
You might want WorkLocation to be immutable so that all changes to them go through User, though I suspect this isn't necessary here.
Update:
You could then add the following methods to User
// This gets filled from the db somehow.
private IList<WorkLocation> workLocations;
// IEnumerable so that all external additions and
// removals must go through dedicated methods.
public IEnumerable<WorkLocation> WorkLocations
{
get { return workLocations; }
}
public void AddWorkLocation(WorkLocation locationToAdd)
{
workLocations.Add(locationToAdd);
// Do whatever else you need to, i.e. mark the item for saving.
}
public void RemoveWorkLocation(WorkLocation locationToRemove)
{
workLocations.Remove(locationToRemove);
// Do whatever else you need to, i.e. mark the item for saving.
}
If you really must get the list of SonOfFoo for some reason, by using simple high level interfaces such as IEnumerable, you're not corrupting the model with implementation details.
Depending on what you need done, it would be better to avoid getting a list of SonOfFoo though, having Foo manage the work would be better.
Also depending on the amount of details SonOfFoo has, it would be a good idea to encapsulate it on an interface with the methods that the UI/Facade would need to use.
Edit:
From your description, the UI needs a list of the WorkLocations a user can work at (a IEnumarable would be a good choice), and then after the user selects the location and confirms it, the UI notifies the control the switch of the user with the selected location.
For my homework, I'm implementing a course registration system for a university and I implemented a simple class for Curriculum with list of semesters and other properties like name of the department, total credits etc.
But I'm wondering if I can inherit this class from a Graph Data Structure with Edges and vertices.
Anybody done similar things before?
My current design is something like this:
public class Curriculum
{
public string NameOfDepartment { get; set; }
public List<Semester> Semesters { get; set; }
public bool IsProgramDesigned { get; set; }
public Curriculum()
{
IsProgramDesigned = false;
}
//
public string AddSemester(Semester semester)
{
As an enterprise architect I would absolutely not use a graph structure for this data. This data is a list and nothing more.
For a problem similar to this, the only reason I would ever consider using a graph structure would be to potentially create the relationship of course requirements and prerequisites.
This way you could then use the graph algorithm to determine if it is valid for a student to register for a class by making sure it is a valid addition to the tree. Same for removing classes, it could be validated to make sure you aren't dropping a class and staying enrolled in the lab for the class example.
Now if I was going to actually implement this. I would still have an overall list of classes that have a Key to the vertex in the graph representation. One thing to keep in mind is that graph algorithms are about the biggest heavy hitter you can throw at a database so minimize the amount of work done to pull the graph out is always key. Depending on the size and scope, I would also evaluate if I could store entire graphs in a serialized form or to use a document database for the same reason.
Which in this example would be the most likely route I would take. I would store the entire object of prerequisites co-requisites and so on right inline with my course object. Since the graph is a set it and done event there's no need to do an actual graph traversal and you're better off storing the pre-calculated graph.
Yes you can inherit this class from a Graph data structure. You can make it a subclass of anything you want (except for a sealed class). The question of whether or not it is a wise design is entirely dependant on what you want to do. I assume you know how, so comment if you need an example of how to implement inheritance.
IF you are wanting to write your own graphing algorithms, why not just model it yourself? It would probably be a fun exercise.