How to Avoid Updating item searched by Dictionary? - c#

In .NET WinForms C# app, I have a Dictionary<string, RefItemDetails> collection named listItems. I store data in it on start of the app. In a static class I have as follows:
// listItems is populated bt reading a file.
// No other operations are performed on it, except finding an item.
public static Dictionary<string, RefItemDetails> itemsList;
// Find RefItemDetails of barcode
public static RefItemDetails FindRefItem(string barcode)
{
RefItemDetails itemDet = null;
try
{
//if (itemsList.TryGetValue(barcode, out itemDet) == false)
// System.Diagnostics.Debug.WriteLine("Barcode " + barcode + " not found in Items");
//itemDet = itemsList.First(item => item.Key == barcode);//.First(item => item.Barcode == barcode);
if (itemsList.ContainsKey(barcode))
itemDet = itemsList[barcode];
}
catch (Exception)
{
itemDet = null;
}
return itemDet;
}
For retrieving an item from listItems in another class, I use :
refScannedItem = null;
// Get Unit Barcode & Search RefItem of it
refScannedItem = UtilityLibrary.FindRefItem(boxItem.UnitBarcode.Trim());
// Display BOX item details
refScannedItem.Barcode = boxItem.BoxBarcode.Trim();
refScannedItem.Description = "BOX of " + boxItem.Quantity + " " + refScannedItem.Description;
refScannedItem.Retail *= boxItem.Quantity;
refScannedItem.CurrentCost *= boxItem.Quantity;
Here what happens above is, I search for an item & I get it "refScannedItem" and I append the Description of it by "BOX of " + boxItem.Quantity + " " + refScannedItem.Description; . So if the original Description was "Aquafina", I make it "BOXof 10 Aquafina". The nest time I scan the same product, I find the product, but now its descrption has become "Box of 10 Aquafina", so my line of setting Description turns to "BOX of 10 BOX of 10 Aquafina". The same goes on like "BOX of 10 BOX of 10 BOX of 10 Aquafina" and so on.
As you cna see in my find code, I had initially used TryGetValue, then tried using LINQ, then tried using ContainsKey, but in all of them why does the value of listItem get updated.
I understand that as TryGetValue has out parameter, so the value is passed as a reference, and then it will be chnaged. But in listItems[key] also updates it !!! How can I avoid this to happen ? I had selected Dictionary collection for easy & fast searching, but this part gives a lot of problems and a big bug too on my app. I couldn't find nay solution where the receive the value but shouldn't be updated. All articles shows how to search & update it.
Kindly suggest a solution for the above. Any help is highly appreciated.
Thanks

You return a pointer to the item contained in your Dictionary, so it makes sense that any manipulations you make to this Object will be stored in the original Dictionary object.
What you want to do is, in FindRefItem, return a pointer to a copy of your RefItemDetails object.
An easy way to do this would be to write a new constructor.
Something like:
public RefItemDetails(RefItemDetails original)
{
this.Barcode = original.Barcode ;
this.Description = original.Description ;
this.Retail = original.Retail ;
this.CurrentCost = original.CurrentCost ;
//Set any other properties here
}
and then replace return itemDet; with return new RefItemDetails(itemDet);

I think you are going about this the wrong way.
You shouldn't have a writeable Description property that you update whenever the quantity changes.
Instead, I think you should have a separate Name property which contains the name of the item (e.g. Aquafina) and a dynamically-created readonly Description property like so:
public string Description
{
get
{
return string.Format("Box of {0} {1}", Quantity, Name);
}
}
Or something along similar lines.

This should do the trick:
if (!refScannedItem.Description.StartsWith("BOX of "))
{
refScannedItem.Description = "BOX of " + boxItem.Quantity + " " + refScannedItem.Description;
}

You are getting an object from a Dictionary - and then changing it, so of course it's properties will change in the Dictionary as well ... you haven't cloned it so why would you be taking a copy?
The solution is quite simply not to change the values of the item and use the amended text in a different way:
var amendedDescription = "BOX of " + boxItem.Quantity + " " + refScannedItem.Description;

Looks like you need to make a copy of the RefItemDetails to make modifications to after you get it back from the call to UtilityLibrary.FindRefItem(boxItem.UnitBarcode.Trim())

Related

C# Fetching a specific value out of an Array

I am desperately trying to adapt an API from which I want to fetch a specific value out of an array and I can't seem capable of doing so.
Specifically, I am trying to fetch a custom field name and value out of the API where the name is Controller and the value is whatever the user gave it a value of (its a string value).
I order to get to this, I need to use what is called an IGame interface, which has several properties and methods within it. All of the properties are used with game proceeded with the name of the property. For example, game.title or game.Platform.
So, doing this.Controller.Text = game.Title; outputs the game title to the UI. So far, so good.
My problem comes when using the methods, whering the custom fields lie. I have to use GetAllCustomFields which has the syntax of ICustomField[] GetAllCustomFields(). The return value is ICustomField[] whose syntax in turn is public interface ICustomField with the properties of GameId, Name, Value.
Unfortunately, the API gives me no further information on actual usage so I'm left to try to figure it out but to no avail.
Here what i have so far:
public void OnSelectionChanged(FilterType filterType, string filterValue, IPlatform platform, IPlatformCategory category, IPlaylist playlist, IGame game)
{
if (game == null)
{
this.Controller.Text = "HellO!";
}
else
{
foreach (string field in game.GetAllCustomFields(ICustomField[Name]))
{
this.Controller.Text = "The " + Name + " is " + Value;
}
}
}
XAML
<Grid>
<TextBox x:Name="Controller" />
</Grid>
Can someone help me restructure the foreach so it actually works?
var controllerFields = game.GetAllCustomFields().Where(f => f.Name == "Controller");
foreach (var field in controllerFields)
{
this.Controller.Text = "The " + field.Name + " is " + field.Value;
}
Or if it is just one Controller-field:
Controller.Text = game.GetAllCustomFields()
.SingleOrDefault(f => f.Name == "Controller")
?.Value ?? "No controller here";
?.Value will return the value of the field if it was found. If not, that question mark will prevent to access .Value because it would lead to a NullReferenceException. By adding ?? "No controller here", you give a fallback which is returned if no Controller field was found. That opererator (?.) is called the null coalescing operator, if you don't know it yet.

C# Excel get the value of a check box

I'm trying to get the value of a check box from an Excel sheet. I found something that appears to come close, but it falls short:
xl.OLEObjects oleObjects = AddressWorksheet.OLEObjects() as xl.OLEObjects;
foreach (xl.OLEObject item in oleObjects)
{
//VBE.CheckBox xlCB = item.Object as VBE.CheckBox;
var xlCB = item.Object as VBE.CheckBox;
Console.WriteLine("checkbox: " + item.Name);
Console.WriteLine("Value: " + xlCB.get_Value());
Marshal.ReleaseComObject(xlCB); xlCB = null;
}
This gives me an error of "Unable to get the Object property of the OLEObject class"
Is there anything that actually works though? Seems like it's something you should be able to do.

Passing multiple variables between pages and using them

I have three variables I'm trying to pass from one page to another: Two checboxlists (just the checked values) and one DateTime.
I'm getting the checked items like this (this is just for one of these checkboxlists which is called lstUsers):
string cblvalues = "";
foreach (ListItem cbitem in lstUsers.Items)
{
if (cbitem.Selected)
{
cblvalues += cbitem.Value + "-";
}
}
cblvalues = cblvalues.Trim('-');
Response.Redirect("Results.aspx?cblvalues=" + cblvalues);
How would I pass the other checkboxlist and the DateTime to "Results.aspx" as well? I've seen a few different examples such as Server.Transfer, and I'm not sure which one is correct here.
And for using them on the Results.aspx page, would I just do:
string cblvalues = Request.QueryString["cblvalues"];
You can put as many values as you like on the query string. (Though as query strings get very long the web server would eventually impose a limit.) Here you simply append one key/value pair:
Response.Redirect("Results.aspx?cblvalues=" + cblvalues);
Just use a & to separate additional key/value pairs:
Response.Redirect("Results.aspx?cblvalues=" + cblvalues + "&moreValue=" + moreValues);
If you do get to the point where the query string becomes absurdly long and you basically have a lot of data to pass to the next page, then you'd be looking at other ways of doing this. A simple alternative may be to store the values in session state, redirect the user, then pull the values from session state. Something as simple as this:
Session["cblvalues"] = cblvalues;
Session["moreValues"] = moreValues;
Response.Redirect("Results.aspx");
Then in Results.aspx you can get the values:
var cblValues = Session["cblvalues"];
// etc.
You might also clear the session values once you get them, if the session doesn't need to keep carrying them:
Session.Remove("cblvalues");
You can pass multiple values through query string by seperated them with a &
so your snippet will be like the following:
Let cblSecond be the second combobox then;
// Building first value here
foreach (ListItem cbitem in cblSecond.Items)
{
if (cbitem.Selected)
{
cblSecondValues += cbitem.Value + "-";
}
}
Response.Redirect("Results.aspx?cblvalues=" + cblvalues + "&cblSecondValues=" + cblSecondValues);
So that you can access them separately like this:
string cblvalues = Request.QueryString["cblvalues"];// gives you the first value
string cblSecondValues= Request.QueryString["cblSecondValues"];// gives you the second value
Response.Redirect(String.Format("Results.aspx?value1={0}&value2={1}&value3={2}", Value1, Value2, Value3));
If you really want to pass them using querystring then you ahouls include them as well
Response.Redirect("Results.aspx?cblvalues=" + cblvalues + "&cblvalues1=" + cblvalues + "&datetimemy=" + datetimevalue);
Form of a query string like below
http://server_name/path/aspxfile?field1=value1&field2=value2&field3=value3..&fieldn=valuen
As other answer mentioned, there are multiple ways like using Session or cookies or as well you can expose those control values as public properties and use then in next page using Page.PreviousPage property but the restriction is that you will have to use either of Server.Transfer() or Server.Execute() method instead of Response.Redirect.

Passing Text & Value in ComboBox

I've tried to make my combobox pass a text and then a value. But i can't get the value.
DropDownList1.Items.Add(new ListItem("abc", 23));
DropDownList1.Items.Add(new ListItem("def", 56));
Then I try get the value when i've selected any of these in the Combobox
string text = DropDownList1.SelectedItem.ToString();
string value = DropDownList1.SelectedValue.ToString();
this.label5.Text = text + " with value: " + value;
This results in a crash with following error code:
"An unhandled exception of type 'System.NullReferenceException' occurred in WindowsFormsApplication1.exe
Additional information: Object reference not set to an instance of an object."
If I just use the "text" variable, everything is fine.
What am I missing?
EDIT: I know that I get null and that will help me not crash, but why is the value not passed on to / from the ComboBox? Thanks in advanced
SOLUTION:
This is how I managed to solve it.
var source = new Dictionary<string, int>();
source.Add("College", 100);
source.Add("T-shirt", 54);
DropDownList1.DataSource = source.ToList();
DropDownList1.DisplayMember = "Key";
DropDownList1.ValueMember = "Value";
And then
private void button1_Click_1(object sender, EventArgs e)
{
var selectedItem = DropDownList1.Text;
if (DropDownList1.SelectedValue == null)
{
return;
}
string value = DropDownList1.SelectedValue.ToString();
//[etc…]
this.label5.Text = "Cloth:" + selectedItem + " costs " + value;
}
Hope this can help anyone.
Thanks all for help!
I've done this quite a long ago. But I think you need to use it like this:
var selectedItem = DropDownList1.SelectedItem;
if (selectedItem != null)
{
string text = selectedItem.Text;
string value = selectedItem.Value;
}
You may need to bind this data before you use it, try it:
myDropdown.DataBind()
Just after adding your items and it may solve it, I think you can find tons and tons of tutorials about it, just Google it
You should add a check to check of i = null like this:
label1.text = DropDownList1.selectedItem.Value != null ? DropDownList1.selectedItem.Text + " with value: " + DropDownList1.selectedItem.Value : label1.text;
This should do the trick it checks if i != null;
you're getting the error because you cant an empty variable with +
// Check whether your combobox is selected or not
if (DropDownList1.SelectedIndex != -1)
{
string text = DropDownList1.SelectedItem.ToString();
string value = DropDownList1.SelectedValue.ToString();
this.label5.Text = text + " with value: " + value;
}
else
{
// message to select option
}
Please note- We have ComboBox in Windows Application and Dropdownlist in Asp.net.
You may need to bind this data before you use it, try it:
myDropdown.DataBind()
Just after adding your items and it may solve it, I think you can find tons and tons of tutorials about it, just Google it
I think there may be none item selected, and you're calling .ToString() in a null value, I cant figure it out without more context, how are you trying to get the selected value?
Since you haven't said which line the exception is thrown on, so it's a bit of a shot in the dark. However:
string value = DropDownList1.SelectedValue.ToString();
DropDownList1.SelectedValue might be null, in which case trying to call ToString() on it would cause a NullReferenceException. Try:
if (DropDownList1.SelectedValue == null)
return;
var value = DropDownList1.SelectedValue;
this.label5.Text = String.Format("{0} with value: {1}", text, value);
//[etc…]
Update:
Assuming that your combobox isn't databound since you are adding items in memory, you need to set the default selected value as well. You would need to find the object's index in the Items collection on your form and then set the SelectedIndex property to the appropriate index.
DropDownList1.Items.Add(new ListItem("abc", 23));
DropDownList1.Items.Add(new ListItem("def", 56));
DropDownList1.SelectedIndex = DropDownList1.Items.IndexOf("abc");
Keep in mind that the IndexOf function may throw an ArgumentException if the item is not in the collection.

How can I output a list of field names and values that were changed?

I'm still learning C# whilst building an MVC web app. Trying to find a way to create a list of values that were changed by a user during an edit operation.
Here's one way I have that would work:
public List<string> SaveVehicleTechnicalInformation(VehicleAssetTechnicalInformationViewModel editmodel)
{
// Create a list of fields that have changed
List<string> changes = new List<string>();
var record = db.VehicleAssetTechnicalInformations.Find((int)editmodel.RecordID);
if (editmodel.Make != null && editmodel.Make != record.Make)
{
changes.Add(" [Make changed from " + record.Make + " to " + editmodel.Make + "] ");
record.Make = editmodel.Make;
}
if (editmodel.Model != null && editmodel.Model != record.Model)
{
changes.Add(" [Model changed from " + record.Model + " to " + editmodel.Model + "] ");
record.Model = editmodel.Model;
}
return changes;
}
But... As you can tell, I am going to need to write an IF/ELSE statement for every single field in my database. There are about 200 fields in there. I'm also worried that it's going to take a long time to work through the list.
Is there some way to go through the list of properties for my object iteratively, comparing them to the database record, changing them if necessary and then outputting a list of what changed.
In pseudo code this is what I guess I am after:
foreach (var field in editmodel)
{
if (field != database.field)
{
// Update the value
// Write a string about what changed
// Add the string to the list of what changed
}
}
Because I'm still learning I would appreciate guidance/tips on what subject matter to read about or where I can independently research the answer. The gaps in my skill are currently stopping me from being able to even research a solution approach.
Thanks in advance.
You can try to use Reflection for your purposes. Something like this
var fields = editmodel.GetType().GetFields();
foreach (var item in fields)
{
if (item.GetValue(editmodel) == database.field)
{
// Update the value
// Write a string about what changed
// Add the string to the list of what changed
}
}
I think I have found the hint I was looking for...
System.Reflection
More specifically, the FieldInfo.GetValue() method.
I was previously unaware of what System.Reflection was all about, so I'll research this area further to find my solution.

Categories