I have a class contains a lot of properties. One of them needs a special UI to be edited.
The user may press edit to this property in the UI then he make changes and either press OK or Cancel
e.g.
class A{
private List<Employee> employees;
public void EditMyEmployees(){
EmployeeEditorForm editor = new EmployeeEditor(employees);
if(editor.ShowDialog() == DialogResult.OK){
employees = editor.GetEditedEmployeesList();
}
}
}
The problem in the previous code that the editor has a copy of the reference to the employees List
and when the editor makes any edits in the List it will be reflected in the original object.
So, pressing OK or Cancel will have the same effect (the object is already updated) and no need for the step
employees = editor.GetEditedEmployeesList();
I know that making deep copy for the employees array before sending it to the editor will solve the problem but still I think this is not the efficient way to do it
I am looking for a design pattern that can make this in a better way.
You don't necessarily need to deep copy the whole collection. You just need to keep track of the elements that changed. Within your EmployeeEditor, use three lists (List<Employee> to keep track of:
Added employees
Removed employees
Changed employees
Upon Cancel, you would need to remove the "added" items, add back the "removed" items, and replace the changed items with their original state.
Note that the changed employees list would need to keep a copy of the original state of the object. If the Employee class has some sort of unique id, you can match cased on that id. Otherwise, the "changed" list would need to be a List<Tuple<Employee, Employee>> so that you can store the matching items.
Also note that, when changes happen in the employees list, you also need to make necessary changes in those three lists. For example, if an new employee is added and then removed, you also need to remove that record from the "added" list. Or it is possible an employee is changed and then removed, in which case you also need to remove from "changed" list.
Having said all this, if I were you, I would make a decision based on the expected use cases and real performance problems (not anticipated performance issues). It is very likely that simply deep copying your collection is the simplest and least error prone way.
There are two kinds of changes involved here: (1) changes to the list (Add / Remove) and (2) changes to individual elements of the list (employees in this case).
Now, part of the problem comes from the semantics of OK/Cancel. If you restrict the scope of these two buttons to changes of the second kind (i.e., changes to the elements of the list), you will be able to handle Remove with a confirmation dialog on this particular action ("Remove such and such"?). For the Addition you don't need anything special, just add a new element to the list. If the user changes their mind they will still have the Remove action available.
For changes on a particular element (second kind) you can use the command pattern as mentioned in the comment. More simply, you could initialize temporary variables for all the fields your editor displays from the element under edition. As the user modifies some values your editor will update the corresponding temporaries. If the user press Cancel you will simply forget those changes (or reinitialize them from the element). If the user press Apply (yes, you should include the Apply button also,) you will now write each of the temporary values onto the corresponding element's attribute. If the user hits OK you would Apply and Close.
Related
I currently have an item database with about 500 (and counting) items in it that's loaded into an array once when the application starts. These items are often accessed (by index) but the array and its contents are never modified during runtime. I'm now needing to create variants of certain items in the database and I'm hoping to do it dynamically during runtime to avoid creating a bunch of item duplicates in the database file itself, as it would more than double the size of it. Since the database will grow in time, I can't simply start assigning the variant ids where the regular item database ids end, as these ids will be saved into user's profiles and they cannot change later.
I've attached a screenshot to make it a little more clearer what the items look like in case it helps. What I'm trying to accomplish in practice is to create X amount of variants of for example the "refined_spear" item for the purpose of cosmetic effects on the items in my game. So for the refined_spear, I'd be creating a duplicate of it, assign it its own id and give it whatever cosmetic effect it should have, and then add it to the items collection.
The way I see it I have a couple of options:
Use a list instead of an array. This would mean that it's no longer viable to access items by index. Not sure how big of a performance hit that would bring.
Create a larger array than is needed, and give the item variants id's that I know the regular database items will never reach. This would leave the array with a ton of null values, but would allow me to continue accessing items by their id.
Simply add the new items in the database file manually
Any input from people wiser than me would be much appreciated!
How to get ObjectId of the recently modified object?
I add some polyline to the drawing. Each one is the same. When one modifies the other, they must also be adjusted to the changes. I need to exclude from the list of objects that need to be updated, the object I just modified. I can not find the answer.
Example:
I have some polyline. When creating them, an event handler is added (ObjectId of each object is added to NOD). At the moment of modifying one of them, the function assigned to the modification will loop through all objects stored in NOD. When the length is changed other objects must also do so. Initially I want to do that the rest will be removed and replaced with a modified copy of the object.
Here I need to access the last modified object to be able to skip it while modifying other polyline. At the moment, the program ends and I think this is a problem because I'm trying to convert the polylines to the same one.
If I understand your problem correctly, what you need is a dynamic exclusion list. A Hashset<ObjectID> instance will serve you well, as ObjectID is a struct (i.e. a value type). See this tutorial:
HashSet is an unordered collection that contains unique elements. We can apply various operations on a HashSet like, Add, Remove, Contains etc.
Once a polyline is modified by user, I am assuming an event triggers your process to go ahead and modify all other polylines in your NOD. To utilize your exclusion list, add a private field to the class that contains your Command Methods:
private static HashSet<ObjectId> exclusionList = new HashSet<ObjectId>();
Make sure to add the ObjectID of the polyline that the user modified to the exclusionList right away:
exclusionList.Add(modifiedObjectID);
The Add() method returns true if the list does not contain the objectID you tried to add, and adds it to the set. It will return false if the set already contains the ObjectID. This is the key to solving your issue. You add each entity to the exclusion set so that each one is only modified once per cycle. Also, since you already added your original polyline's ObjectID to the set, it will never be modified in the loop. After the loop ends, clear the list and wait for the next time the user modifies an entity.
In your loop that cycles through your MOD, do the following:
public void ProcessEntities()
{
foreach(DBDictionaryEntry obj in MyNOD)
{
//Add each objectID to your exclusion List
//if it's already there, everything inside the if statement is skipped!
if(exclusionList.Add(obj.Value))
{
//do your object modification here
}
}
//All entities have been processed now
//clear the list and wait for the next event
exclusionList.Clear();
}
I am building a custom small interpreted script language and everything is working just fine except the scoping.
For the actual execution I am using a visitor pattern:
I modified the pattern to pass through the Variable Table:
public void visit(ProgrammTree proTree){
VariableTable vt = new VariableTable();
foreach (var t in proTree.getChildren()) {
t.accept(this, vt);
}
}
And here is where the problem starts:
public void visit(WhileTree whiletree, VariableTable vt) {
var cond = (ConditionTree)whiletree.getChild(0);
while (cond.accept(this, vt).toBoolean()) {
var clonedSubTable = new VariableTable(vt)
foreach (Tree t in whiletree.getChildren()) {
t.accept(this, clonedSubTable );
}
}
}
Problem is that changes within the loop are not performed in the outer scope.
Do you have a smart way to implement this?
You left a couple of things a bit vague, so I'm going to make the following assumptions (please point out any that are wrong):
Your VariableTable maps variable names directly to their associated value
Whenever you assign a value, you directly set that value as the entry in the table (without going through any layer of indirection)
Your cloned variable tables do not keep a reference to the original and don't propagate any changes to the original
So under these assumption the problem is that any assignments done using the cloned table won't be visible in the original table even in cases where the assigned-to variable was already present in the original table.
To fix this, there are multiple approaches:
You can make your table map variables to memory locations rather than values. You'd then have another table (or just a plain array) that maps memory locations to values. This way the table-entry for a variable would never change: Once the variable is defined, it gets a memory address and that address isn't going to change until the variable dies. Only the value at the address may change.
A quick-and-dirty alternative to that approach that keeps you from having to manage your own memory would be to add a mutable wrapper around your values, i.e. a ValueWrapper class with a setValue method. Assuming that your cloned table is a shallow copy of the original, that means that you can call setValue on an entry of the cloned table and, if that entry was already present in the original table, the change will also be reflected in the original table.
The solution that keeps closest to your current code would be to turn your table into a linked structure. Then new VariableTable(vt) would not actually copy anything, but simply create a new empty table with a parent link pointing to the original table. Any new entries would be inserted into the new table, but accesses to old entries would simply be propagated to the parent table.
Even if you choose to go with options 1 or 2 to solve your current problem, using a parent link instead of copying the table constantly would be a good idea anyway for performance reasons.
The downside of only going with solution 3 would be that you'll run into similar problems again when you implement closures. So it really only fixes your exact current problem.
The upside of solution 1 is that it allows you full control over your memory, so you have free hand in implementing features related to memory in any way you want. The down side is the same.
May sound like a dumb question but here goes.
I instantiate a LIST from my homepage, the list is in a global class file, and returns all the information about the person logging in. the person, could have one or more accounts associated with the site, and therefore i need to code against a default flag to display their default account informaiton. However, i then also need to build their other account information and display this for them.
The additional account(s) are listed in a drop down box. when the drop down box fires off, instead of calling out to the class again, and retrieving all the necessary information, as i've already done this once, how can i store the object, so that it can be used?
I've looked at Session Variables, but this gets a bit messy (I have 35 fields being returned in my list), plus, the Session variables only get set the first time around, not on DDL changed.
therefore, I need a way of having quick access to the object. - what's the best approach?
As per me , Session is the best possible object for your type of requirement and on DDL changed event try to rebind the Session object with new modified values
I'm writing a workflow that needs to perform certain actions depending on which fields are changed when someone edit's an item. For example, if a user goes in and removes a role (job) from an item (staff member) then I need the workflow to realise that the role field was changed, deduce which role was removed (or potentially added) and then notify the manager of that role and do any other necessary tasks. Another example would be if the address fields in an item get changed then the appropiate HR department need to be notified of the change.
To do this I'm going to try a code block when the workflow is started that compares the top two history entries and any fields that differ will be flagged as changed and I'll take the appropriate actions dependent on each field.
Could anyone please tell me what the other options are for getting this functionality as I'd like to know if there's a better way. Thanks
Using SPD workflows it would not be that hard, depending on number of roles.
Create a column and then go into the content type and hide it. Create a SPD workflow that executes on new or change. Compare the hidden column and the one the user entered, if changed compare values against a role name and do what needs to be done. When that is done copy the user entered column into the hidden column.
Ugly and long but if you don't have the abaility to get workflow code implemented on the server, thanks corporate IT, then it is an option.
I would enable versioning on the list and then use:
SPListItem currentItem = workflowProperties.Item;
SPListItemVersion previousItemVersion = currentItem.Versions[1];
//Compare the fields in currentItem and previousItemVersion
But if i understand your question correctly, that’s what you’re about to do already.