I have an application that allows a user to select items from a tree structure that are then passed to a method that builds a report. The item is the smallest level of granularity and contains an id value. I need to produce an enumerable object that can be used to produce both summery level reports and individual item reports. For example, the picture bellow shows the tree and the desire report structure.
What I need is to be able to identify or flag items that need to be printed individually. In other words if item is not found in any child groups then mark it as needs to print individual. This is important because it is possible for the item to exist in more than one grouping. How can I parse through the tree and check if the item exists in a child node?
The Item and ItemSet(groups) classes are as follows:
public class Item
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public int Property3 { get; set; }
public int Property4 { get; set; }
}
public class ItemSet
{
public List<Item> Items { get; set; }
//.
//.
//.
//.
public List<ItemSet> ItemSets { get; set; }
}
Notice that an itemset can contain other item sets. Also, the list of Items includes all items including item in children. I need a mechanism to check for if the item exists at that level alone.
UPDATE
To further clarify, I have added summarized class diagrams to illustrate the relationships/composition of Items, ItemSets, and the application as a whole.This is a legacy code base so and so i do not have much flexibility and must make do with most of what is in existence. When getAllItems() is called on a partiular set, it returns all of its decedents, even if it is an item the belongs to a nested set. I need to be able to determine if it is a direct decedent or a child of a sub set.
foreach (var item in itemSet.getAllItems())
{
if (item.Parent == itemSet)
{
// Is child of itemSet
}
else
{
// Is descendant of nested itemSet
}
}
Related
I'm new in C# and I am completing the book "Microsoft Visual C# 2013 Step by Step" written by John Sharp.
An exercise, regarding "Generics", I found this code:
public class Tree<TItem> where TItem : IComparable<TItem>
{
public TItem NodeData { get; set; }
public Tree<TItem> LeftTree { get; set; }
public Tree<TItem> RightTree { get; set; }
public Tree(TItem nodeValue)
{
this.NodeData = nodeValue;
this.LeftTree = null;
this.RightTree = null;
}
public void Insert(TItem newItem)
{
TItem currentNodeValue = this.NodeData;
if (currentNodeValue.CompareTo(newItem) > 0)
{
// Insert the new item into the left subtree
// code here....
}
else
{
// Insert the new item into the right subtree
// code here....
}
}
}
I can't understand why he defined the properties in different mode.
One in this way:
public TItem NodeData { get; set; }
And the others in this:
public Tree<TItem> LeftTree { get; set; }
public Tree<TItem> RightTree { get; set; }
Someone can explain me why? Thank you
These properties are being used for different things. As their name suggest:
NodeData is used to facilitate the information stored in the tree.
LeftTree/RightTree are there to facilitate the topology of the tree - each current object (node) is basically a root of a tree rooted at itself. So as it is a binary tree it has two direct descendants - the left and the right nodes.
Where the part where the generics come to play is about the what is the kind of data stored in the tree. So the NodeData is trivially of "type" TItem. The left and right nodes are of type Tree<TItem> so to ensure that at any depth of the tree it is a TItem type of data that is stored.
To make it simpler lets suppose that you wanted to create a binary tree of integers. Then you'd model it by:
public class Tree
{
public int Data { get; set; }
public Tree Left {get; set; }
public Tree Right {get; set; }
}
I think this way you can really see what is the fundamental difference between the Data and Left, Right properties.
He defines a tree. The NodeData property is the current node value. Then if the value is smaller than the the current node, the new value is put on the left, otherwise on the right. If the type of LeftValue and RightValue are Tree, it's to have a parent-child structure. This class allows to create a data structure like binary tree.
I tried creating a Binary tree assuming it will have max of 2 child nodes. But for a graph it will have one or more graph nodes connected to it. How can I create a simple class for a graph node like the below which I created for a tree. The reason for suggestion is because I am trying for a simple code to find all nodes info tied to a particular node.
class TreeNode
{
public int value { get; set; }
public TreeNode leftNode { get; set; }
public TreeNode rightNode { get; set; }
}
In case of graph, any node can have arbitrary many edges (neighbor nodes), so you have to use a collection, say List<T>:
// TValue - let's generalize
// (e.g. you may want ot have double or string value associated with the node)
class GraphNode<TValue> {
private List<GraphNode<TValue>> m_Connected = new List<GraphNode<TValue>>();
public TValue value { get; set; }
// get (and no set) - we don't want to assign the collection as whole
// if we want to add/remove a neighbor we'll call Neighbors.Add, Neighbors.Remove
public List<GraphNode<TValue>> Neighbors {
get {
return m_Connected;
}
}
}
I have a general question about the structure of my object model. Perhaps I am approaching this with tunnel vision from the wrong direction. I have two classes, Item and SerializedItem. I have defined them as such:
public class Item
{
public string ItemNumber { get; set; }
public string Description { get; set; }
public double Cost { get; set; }
}
public class SerializedItem : Item
{
public string SerialNumber { get; set; }
public MyObject Location { get; set; }
}
An Item is a generic definition of an item, and contains information common to that product. SerializedItem is a representation of a specific, physical item. My difficulty lies in the fact that only one Item with a particular ItemNumber should exist in memory at anytime, and I am not sure the best pattern to use to enforce that constraint while allowing a SerializedItem to act as its base type.
Maybe this is a more appropriate approach? I don't have a lot of experience using the 'New' keyword, and I've shied away from using it in the past in favor of an inheritance structure that didn't require its use.
public class Item
{
public string ItemNumber { get; set; }
public string Description { get; set; }
public double Cost { get; set; }
}
public class SerializedItem : Item
{
private Items _item;
public SerializedItemz(Item item)
{
_item = item;
}
public new string ItemNumber
{
get { return _item.ItemNumber; }
set { _item.ItemNumber = value; }
}
public new string Description
{
get { return _item.Description; }
set { _item.Description = value; }
}
public new double Cost
{
get { return _item.Cost; }
set { _item.Cost = value; }
}
public string SerialNumber { get; set; }
}
I would appreciate any guidance on how to approach this. I'm not tied to any particular solution.
To provide some clarity:
The Item class is a representation of a particular product, 'Widget A.' It has information about the Widget A's cost, weight, dimensions, etc. No matter how many Widget As are produced, they all share this information.
The SerializedItem class is a representation of an actual item in that product line, 'Widget A 001.' It contains information about the physical location of that item and it's production and sales history.
If the Item object is updated, all SerializedItems should reflect that change.
I am not sure the best pattern to use to enforce that constraint while allowing a SerializedItem to act as its base type
At first glance a flyweight factory pattern would seem appropriate. Create a class whose responsibility is to create Items, keep track of which ones have already been created, and ensure that only one item with a given key is created.
You can also build logic into the factory to create different subtypes like SerializedItem - you'd just need to provide the appropriate SPI to determine what type is necessary and collect the necessary inputs.
A basic implementation would look something like:
public static class ItemFactory
{
public static Dictionary<string, Item> _Items = new Dictionary<string, Item>;
public static Item GetItem(string itemNumber)
{
if(!_Items.ContainsKey(itemNumber))
{
_Items[itemNumber] = new Item(itemNumber);
// Initialize item if necessary
}
return _Items[itemNumber];
}
}
The SerializedItem class is a representation of an actual item in that product line
Than an appropriate design is to make Item an ItemType and use composition instead of inheritance. So your second approach (with the change that SerializedItem does NOT inherit from Item) looks valid.
If Item is truly a non-instantiated base class then mark it as abstract and work through your concrete SerializedItem class ( and any other derived classes you may have ). If you only want a single Item in memory with a given item number then you might consider a Dictionary type collection indexed on the item number.
I need to build a typed list of parent-child objects that are read from two different Excel sources: One describes parent object, another describes child objects. The hierarchy is only 2 layers ever.
Reading into excel is not the issue, as it is read into 2 untyped datatables, but joining the information is.
The structure is very plain:
Parent has an ID and some text fields
Children have a parentID (so its 1-m) and some text fields
The objects that these are to be populated into looks like this:
public class ParkingSites
{
public List<ParkingLot> Lots { get; set; }
public ParkingSites(List<ParkingLot> arg)
{
Lots = arg;
}
}
public class ParkingLot
{
public List<Bay> Bays{ get; set; }
public int Id { get; set; }
public List<string> ParkingLotDetails { get; set; }
public ParkingLot()
{
}
}
public class Bay
{
public List<string> BayDetails { get; set; }
public int ParentId { get; set; }
public Bay()
{
}
}
The excel sources have a fixed column order with the parent sheet's first column being the parentId, and the first column on the child sheet also being the parentId.
EDIT: After playing around a bit, I just made both parent and child classes typed, as the initial reason for leaving them mostly untyped lead to more problems than it prevented. This is part of a larger project where the untypedness is a better solution for our problem on the other classes with data that is not hierarchial.
You can simply group the list of children by the parent id, and then iterate over the parents and add each child that belongs to it.
For example, you could use ToLookup:
// assuming you have all Bay instances in a collection called bays
var baymap = bays.ToLookup(b => b.ParentId);
// and all ParkingLot instances in a collection called lots
foreach(var lot in lots)
lot.Bays.AddRange(baymap[lot.Id]);
or, using the first element in the details lists:
var baymap = bays.ToLookup(b => b.BayDetails[0]);
foreach(var lot in lots)
lot.Bays.AddRange(baymap[lot.ParkingLotDetails[0]]);
or, using Where without a lookup (probably slower, depends on your data):
foreach(var lot in lots)
lot.Bays.AddRange(bays.Where(b => b.ParentId == lot.Id));
I have a collection of complex models each containing a collection of interface instances to other complex models and I need to display these parent and child complex models, allowing all properties of the parent and child complex models to be edited.
How can I best display this data and allow editing of the parent and child object's properties individually as well as through a combination of the selection of multiple cells and a context menu click (i.e. change the same property value on a child model across multiple parents)? I also need to be able to perform actions like setting model property values to some other complex model instance via search from within the editing mechanism (DataGrid cell currently)?
Below is a generic example of classes that approximates what I am working with in the application.
enum ChildType
{
One,
Two,
Three
}
class ComplexType
{
public long ID { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
class IChildModel
{
ChildType Type { get; set; }
string Name { get; set; }
}
class ChildModel1 : IChildModel
{
public ChildType Type { get; set; }
public string Name { get; set; }
public string Property1 { get; set; }
public decimal Property2 { get; set; }
public ComplexType Property3 { get; set; }
}
class ChildModel2 : IChildModel
{
public ChildType Type { get; set; }
public long Property1 { get; set; }
public string Property2 { get; set; }
}
class Parent
{
public long ID { get; set; }
public string Name { get; set; }
public CustomObservableCollection<IChildModel> Children { get; set; }
}
class ViewModel
{
public CustomObservableCollection<Parent> Parents { get; set; }
}
Thus far I have implemented the application using a DataGrid and dynamically generated the columns in the View code-behind using reflection. The binding of the columns for the child complex object instances uses a subscript on the CustomObservableCollection<> (custom collection allowing indexing by an generic value [enum ChildType] in this case). The binding in particular has made it difficult to properly set a value on a same property across multiple parent's child instances (via multi-select on a column and a context menu click to set a value). Again, I am handling these sort of mass changes in the code-behind on the View, using reflection a binding path parsing to set the property values (it feels wrong; hate doing it that way). I would like to be able to set the selected children on the ViewModel and pass the property name and new value for the property to a command in the ViewModel to make the changes. Even being able to pass the command the child type, property and new value would be nice (I think).
My research through Google, stackoverflow, Code Project, etc. has pointed me toward my current solution but I feel I am thinking about the problem incorrectly and there should be a better MVVM approach to this.
EDIT
The primary focus for this application is to allow the editing of multiple parent and child model instances in a view where the user can compare values of several instances and be allowed to set the value of a parent or child property across multiple objects of the same type to the same value (i.e. Parent1 and Parent2 both have a ChildModel1 and user wants to set the Name on Property3 of both parent objects' ChildModel1 to "X"). Although, the application still must allow individual edits of properties on parent and child objects (DataGrid does seem to fill the requirement nicely). In meeting these requirements, I implemented dynamic column creation in the view. Below is a generic example of what this logic looks like.
private void DataGrid_TargetUpdated(object sender, DataTransferEventArgs e)
{
var vm = DataContext as ViewModel;
if (vm != null && vm.Parents != null) {
List<ChildType> processedChildTypes = new List<ChildType>();
foreach (var parent in vm.Parents) {
for (int childIndex = 0; childIndex < parent.Children.Count; ++childIndex) {
var child = vm.Children[childIndex];
if (!processedChildTypes.Contains(child.Type)) { // Ensure each child type is only processed once
processedChildTypes.Add(child.Type);
CreateChildPropertyColumns(processedChildTypes, child);
}
}
}
}
private void CreateChildPropertyColumns(List<ChildType> processedChildTypes, IChildModel child)
{
PropertyInfo[] childProperties = child.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); // Only use properties declared on the child type
Type childInterfaceType = typeof(IChildModel);
foreach (PropertyInfo childProperty in childProperties) {
// Only create a column if the property is editable
if (childProperty.CanWrite) {
if (childInterfaceType.IsAssignableFrom(childProperty.PropertyType)) {
var subChild = childProperty.GetValue(child, null) as IChildModel;
if (subChild != null && !processedChildTypes.Contains(subChild.Type)) {
processedChildTypes.Add(subChild.Type);
CreateChildPropertyColumns(processedChildTypes, subChild);
}
}
else
dataGrid.Columns.Add(CreateChildPropertyColumn(child.Type, childProperty));
}
}
}
private DataGridColumn CreateChildPropertyColumn(ChildType childType, PropertyInfo propertyInfo)
{
DataGridColumn column = null;
var binding = new Binding(string.Format("Children[{0}].{1}", childType, propertyInfo.Name));
/* Create column based on PropertyInfo here */
/* Default case is a text column */
column = new DataGridTextColumn() { Binding = binding };
column.Header = propertyInfo.Name;
return column;
}
I think it's not a good idea to use DataGrid in this situation. Most of the time, users rarely view/edit MULTIPLE Parent, ChildModel2, and the ComplexType at once.
You have to think about how users are going to view/edit the data and come up with a simpler UI. For example, if users view/edit Parent and ChildModels most of the time and rarely view/edit ComplexType then you can put textboxes to edit the parent and a DataGrid to edit its ChildModels.
This way, you have simpler UI and a lot easier to write code. I think it's much more complicate to write code that save multiple Parent as in this example.