Why won't my drop down default to the given value? - c#

I've created a SelectList from a enum. The enum has a description, and the int value is being set to the value I want to store in the database.
The problem is, the default (BLANK) I set on construction isn't being used.
This is my enum:
public enum Stage
{
[Description("")]
BLANK = -99,
[Description("No Data")]
NoData = 9999,
[Description("Nil")]
Nil = 0,
[Description("Action")]
SAction = 1,
[Description("Action Plus")]
SActionPlus = 2,
[Description("Full")]
Full = 3
}
I create it in my controller:
private static IEnumerable<SelectListItem> GenerateSenStageList()
{
var values = from Stage e in Enum.GetValues(typeof(Stage))
select new { ID = (int)e, Name = e.ToDescription() };
return new SelectList(values, "Id", "Name", (int)Stage.BLANK);
}
Where I thought the final parameter set the selected item.
I assign it as ViewData, and access it like:
<%= Html.DropDownList("Stage", (IEnumerable<SelectListItem>)ViewData["StageList"])%>
However, Nil is always the selected value.
What am I missing here??
Thanks!

The last parameter does determine the selected value. However, you are passing a Stage enumerated value as the last parameter, while the actual elements of your list are made up of an ID value and a Stage value. To make this work, you have to pass it the actual object from values with a Stage value of BLANK.

Iainie,
Using your code, i managed to get this working first time. here's my amended code (using the accountcontroller for testing) [using .net 3.5]:
// from account controller - put the enum, etc in there for brevity
public enum Stage
{
[Description("")]
BLANK = -99,
[Description("No Data")]
NoData = 9999,
[Description("Nil")]
Nil = 0,
[Description("Action")]
SAction = 1,
[Description("Action Plus")]
SActionPlus = 2,
[Description("Full")]
Full = 3
}
public static IEnumerable<SelectListItem> GenerateSenStageList()
{
var values = from Stage e in Enum.GetValues(typeof(Stage))
select new { ID = (int)e, Name = e.ToDescription() };
var sellist= new SelectList(values, "Id", "Name", (int)Stage.BLANK);
return sellist;
}
public virtual ActionResult LogOn()
{
var res = GenerateSenStageList();
ViewData["StageList"] = res;
return View();
}
// the ToDescription() extension method
public static class Extn
{
public static string ToDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
var attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
}
// then in the LogOn view:
<%= Html.DropDownList("Stage", (IEnumerable<SelectListItem>)ViewData["StageList"])%>
this all works exactly as you'd hoped for, so I'm wondering if your invocation from the view is somehow getting a bit fuddled. try my example above and see if there are any subtle differences in the selectlist generated code etc.

Just a guess, but:
You cast the ViewData["StageList"] to IEnumerable<SelectListItem>. That enumerable may be the SelectList that you created in the Controller, but it does not have the SelectedValue property.
Maybe it works if you cast ViewData["StageList"] to SelectList instead?
<%= Html.DropDownList("Stage", (SelectList)ViewData["StageList"])%>
In this case using the interface may be the wrong thing, because you actually need the information provided by the SelectList object.

#Ken Wayne VanderLinde is right. If you are using C# 4.0, then you can do this to populate the selected value:
private static IEnumerable<SelectListItem> GenerateSenStageList()
{
var values = from Stage e in Enum.GetValues(typeof(Stage))
select new { ID = (int)e, Name = e.ToDescription() };
return new SelectList(values, "Id", "Name", values.Cast<dynamic>().Where(x => (x.ID == (int)Stage.BLANK)));
}

Related

.Net Core, merge two lists, remove invalid entries and keep values in the original list

I have a default list of attributes and in incoming list of attributes. I need to remove any items from the incoming list that do now match the Name in the default list. I have tried many different LINQ queries, but have not been able to accomplish this task.
Default List:
Attributes[] defaultAttributes =
{
new ProfileAttributes() { Name = "FirstName", Include = false, Required = false },
new ProfileAttributes() { Name = "MiddleName", Include = false, Required = false },
new ProfileAttributes() { Name = "HomeCountry", Include = false, Required = false },
...
I want to merge the two lists and remove any items where the Name of the incoming list does not match the default list.
For example in the following remove Favorite color because it is an invalid name and preserve the required values.
Attributes[] incomingAttributes =
{
new ProfileAttributes() { Name = "FavoriteColor", Required = true },
new ProfileAttributes() { Name = "MiddleName", Required = false},
new ProfileAttributes() { Name = "HomeCountry", Required = true },
Most incoming lists will not have "Include" So I need to add that and set it to true if it is in the incoming list, otherwise false. I have done that with the following, but interested if there is a way to combine this with the merge.
Revised, I used the following solution:
I used lists instead of array lists. I found this easier to loop through and bind to checkboxes on the form
Attributes[] defaultAttributes
to
List<ProfileAttributes> defaultAttributes = new List<ProfileAttributes>()
Inside the loop for my form:
<input type="checkbox"for="myModel.ProfileAttributes[i].Include"
I created an empty list:
List<ProfileAttributes> validListAttributes = new();
Then I created a loop. If the name is valid add it to the empty list and add the Include attribute:
foreach (var a in myModel.ProfileAttributes) //incomingAttributes
{
if (defaultAttributes.Any(d => d.Name == a.Name))
{
a.Include = true;
validListAttributes.Add(a);
}
}
Then another loop to add missing attributes because all attributes must be display on the form:
foreach (var d in defaultAttributes)
{
if (!validListAttributes.Any(v => v.Name == d.Name))
{
validListAttributes.Add(d);
}
}
Then update the model with the valid list containing all attributes:
myModel.ProfileAttributes = validListAttributes.ToList();
This will be a lot easier with a generic IEqualityComparer whose job is to compare the Name property of the instances involved in the process.
So let's define an IEqualityComparer for the Attributes class
public class ProfileAttributesComparer : IEqualityComparer<ProfileAttributes>
{
public bool Equals(ProfileAttributes obj1, ProfileAttributes obj2)
{
if(obj1 == null && obj2 == null)
return true;
if(obj1 == null || obj2 == null)
return false;
var result = string.Compare(obj1.Name, obj2.Name,
StringComparison.CurrentCultureIgnoreCase);
return result == 0;
}
public int GetHashCode(ProfileAttributes obj)
{
return obj.Name.GetHashCode();
}
}
Now you can process the elements in the incomingAttributes that have a name equal to an instance inside the defaultAttributes and change the property Include to true
var result = incomingAttributes
.Where(x => defaultAttributes.Contains(x, new ProfileAttributesComparer()))
.Select(p => { p.Include = true; return p;});
The result variable contains only the items with the same name but the incomingAttributes list still has three items and two of them have the Include property changed to true.

How to cache data asp.net mvc using Cache obect

I am using data caching in my asp.net application.
This is my interface for the ICacheProvider.cs
public interface ICacheProvider
{
object Get(string key);
void Set(string key, object data, int cacheTime);
bool IsSet(string key);
void Invalidate(string key);
}
This the way I'm using caching in the services.
public List<EmployeeLookUp> GetEmployeeLookUp(RecordStatusEnum recordStatusEnum, int locatioId)
{
var status = (int)recordStatusEnum;
var employeeData = Cache.Get("EmployeeLookUp") as IEnumerable;
if (employeeData == null)
{
var result = MyDb.Employee.Where(w => w.Status == status && w.LocationId == locatioId).ToList().Select(s => new EmployeeLookUp()
{
EmployeeId = s.EmployeeId,
DepartmentId = s.DepartmentId,
EmployeeValue = string.Format("{0}{1}{2} {3} {4}", "[", s.CustomEmployeeId, "]", s.FirstName, s.LastName)
}).ToList();
if (result.Any())
Cache.Set("EmployeeLookUp", result, 30);
return result;
}
return (List<EmployeeLookUp>) employeeData;
}
In the controller I'm using the returned of employees like this.
public ActionResult Index()
{
var employees = _employeeServices.GetEmployeeLookUp(RecordStatusEnum.Active, User.GetCemexUser().LocationId);
employees.Insert(0, new EmployeeLookUp() { EmployeeId = -1, EmployeeValue = "All" });
var complexRosterViewModel = new ComplexRosterViewModel
{
EmployeeList = new SelectList(employees, "EmployeeId", "EmployeeValue"),
ListEmployeeGroups = new SelectList(_employeeGroupServices.GetEmployeeGroup(RecordStatusEnum.Active, User.GetCemexUser().LocationId), "EmployeeGroupId", "Value"),
ListDepartments = new SelectList(_departmentService.GetDepartments(RecordStatusEnum.Active,User.GetCemexUser().LocationId),"DepartmentId","Value")
};
return View(complexRosterViewModel);
}
Now my problem is, when i'm reloading the page several times, the additional "All" option that I added additionally to the employee select list, has been added to cached object("EmployeeLookUp") several times. How this can be possible? I do not want the "All" option to be cached.
It happens because you're using a reference to cached object.
If you change the object, it will reflect the changes in cached data.
Asp.Net Cache, modify an object from cache and it changes the cached value
You must clone the object or create a new and copy the properties values (you can use AutoMapper to do it for you)
Hope it helps.

Sorting a class string field property with numerical value [duplicate]

This question already has answers here:
Sorting of list contained strings having alphabetic/numeric
(2 answers)
Closed 8 years ago.
I have a class with one property "Name" containing names like "1_[AnnualRevenue]","2_[ResellerType]","3_xxx"....
my class is like
class xxx
{
private string fileName;
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
}
And I am assigning the values to the object of the class. like xxx.FileName="1_[AnnualRevenue]";
Now I have a list class. And now sort the list according to this class property.
Now I want to sort the field according to the numeric order, I mean 1 first 2 second and so on.
And then write it to filestream.
Could any body help me with this.
Thanks in advance.
Since the property is a String but you want to sort it numerically, probably the best way would be to implement IComparable on your class and then put your custom sort code in the CompareTo method. Then you don't have to write a more complex Lambda statement each time you want to Sort a list, you can just call the Sort() method on the list.
You can also handle cases where the FileName property does not contain an underscore or is null, rather than getting exceptions in your OrderBy code (which is what would happen with most of the other answers).
I made a couple of other changes also - override the ToString method so you can easily display the value to the console window, and used Automatic property syntax for the FileName property so we can remove the backing field:
class xxx : IComparable<xxx>
{
public string FileName { get; set; }
public int CompareTo(xxx other)
{
// Short circuit if any object is null, if the
// Filenames equal each other, or they're empty
if (other == null) return 1;
if (FileName == null) return (other.FileName == null) ? 0 : -1;
if (other.FileName == null) return 1;
if (FileName.Equals(other.FileName)) return 0;
if (string.IsNullOrWhiteSpace(FileName))
return (string.IsNullOrWhiteSpace(other.FileName)) ? 0 : -1;
if (string.IsNullOrWhiteSpace(other.FileName)) return 1;
// Next, try to get the numeric portion of the string to compare
int thisIndex;
int otherIndex;
var thisSuccess = int.TryParse(FileName.Split('_')[0], out thisIndex);
var otherSuccess = int.TryParse(other.FileName.Split('_')[0], out otherIndex);
// If we couldn't get the numeric portion of the string, use int.MaxValue
if (!thisSuccess)
{
// If neither has a numeric portion, just use default string comparison
if (!otherSuccess) return FileName.CompareTo(other.FileName);
thisIndex = int.MaxValue;
}
if (!otherSuccess) otherIndex = int.MaxValue;
// Return the comparison of the numeric portion of the two filenames
return thisIndex.CompareTo(otherIndex);
}
public override string ToString()
{
return FileName;
}
}
Now, you can just call Sort on your list:
List<xxx> list = new List<xxx>
{
new xxx {FileName = "13_a"},
new xxx {FileName = "8_a"},
new xxx {FileName = null},
new xxx {FileName = "1_a"},
new xxx {FileName = "zinvalid"},
new xxx {FileName = "2_a"},
new xxx {FileName = ""},
new xxx {FileName = "invalid"}
};
list.Sort();
Console.WriteLine(string.Join("\n", list));
// Output (note the first two are the empty string and the null value):
//
//
// 1_a
// 2_a
// 8_a
// 13_a
// invalid
// zinvalid
You can use LINQ to do that for you
List<xxx> orderedList = unOrderedList.OrderBy(o => Convert.ToInt32(o.FileName.Split('_').First())).ToList();
Editted the answer on behalf of the comments - pointing out that indeed we need to convert to integers to order correctly.
You can do like following to sort the list:
List<xxx> list = new List<xxx>
{
new xxx { FileName = "3_a" },
new xxx { FileName = "1_a" },
new xxx { FileName = "2_a" },
new xxx { FileName = "8_a" }
};
var sorted = list.OrderBy(it => Convert.ToInt32(it.FileName.Split('_')[0]));//using System.Linq;
And you can write the list to disk file as below:
using (TextWriter tw = new StreamWriter("C:\\FileNames.txt"))
{
foreach (var item in sorted)
{
tw.WriteLine(item.FileName.ToString());
}
}

How to use LINQ to CRM to populate Entity Readonly Fields (ModifiedOn, Createdby, etc)?

I'm trying to run this simple query:
var appt = (from a in context.AppointmentSet
select new Appointment{ ModifiedOn = a.ModifiedOn}).First();
but I'm getting a compiler exception since ModifiedOn is readonly.
I could just return a, but then all the attributes of the Appointment entity will be returned, not just the ModifiedOn.
I could return new { a.ModifiedOn }, but then appt would be an AnonymousType and not an Appointment.
What's the suggested way to make this work?
Note, this is an example, assume that I'm returning more than just a single property from Appointment, and then there is a where criteria of some sort
I always do it like that:
var appt = (from a in context.AppointmentSet
select new Appointment {
Attributes =
{
{ "modifiedon", a.ModifiedOn },
{ "createdon", a.CreatedOn },
{ "createdby", a.CreatedBy }
}
})
.First();
It does not require any extra coding, I'm really surprised nobody posted that here yet.
This is the most efficient way I can think of:
Create a new constructor that accepts an AnonymousType (Object)
public Appointment(object anonymousType) : this()
{
foreach (var p in anonymousType.GetType().GetProperties())
{
var value = p.GetValue(anonymousType);
if (p.PropertyType == typeof(Guid))
{
// Type is Guid, must be Id
base.Id = (Guid)value;
Attributes["opportunityid"] = base.Id;
}
else if (p.Name == "FormattedValues")
{
// Add Support for FormattedValues
FormattedValues.AddRange((FormattedValueCollection)value);
}
else
{
Attributes[p.Name.ToLower()] = value;
}
}
}
Then call it like so:
var appt = (from a in context.AppointmentSet
select new Appointment(new { a.ModifiedOn })).First();
It has to reflect over all the properties of the AnoymousType, but it should work and has the added benefit of not having to rewrite the properties names each time.

How to fetch value of enum?

I have defined an enum like
public Enum CompanyQuarters
{
First=1,
Second=2,
Third=3,
Fourth=4
}
I bind them to dropdown list like
ddlCompQuarter.DataSource = Enum.GetNames(typeof(CompanyQuarters));
ddlCompQuarter.DataBind();
Now I want to fetch the dropdownlist selected value For e.g for selection 'second' I like to fetch 2 ?
This does not work
int selectedVal = int.Parse(ddlCompQuarter.SelectedValue.ToString());
ActiveQuarters value = (ActiveQuarters)Enum.Parse(typeof(ActiveQuarters),ddlCompQuarter.SelectedValue.ToString());
or if you are using Dot Net Framework 4 or greater, see Enum.TryParse
ActiveQuarters value;
Enum.TryParse<ActiveQuarters>(ddlCompQuarter.SelectedValue.ToString(), out value);
Here I am showing you the best way to use enum:
public enum enumVIPBusinessPlanPaymentType {
[Description("Monthly")]
Monthly = 1,
[Description("Paid In Full (PIF)")]
PaidInFull = 2,
[Description("Barter")]
Barter = 3 }
and create a EnumHelper.cs class to read its value or description
public static Int32 GetIntValue(Enum en)
{
Type type = en.GetType();
return TemplateControlExtension.GetInt32(null, en);
}
public static string GetStringNameFromValue(Enum en)
{
Type type = en.GetType();
MemberInfo[] info = type.GetMember(en.ToString());
if (info != null && info.Length > 0)
{
object[] attrs = info[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
return ((DescriptionAttribute)attrs[0]).Description;
}
}
return TemplateControlExtension.GetString(null, en);
}
I hope it will like you
ActiveQuarters typedValue = (ActiveQuarters)Enum.Parse(typeof(ActiveQuarters),
ddlCompQuarter.SelectedValue);
// If you need numeric value
int numericValue = (int)typedValue;
CompanyQuarters comp= (CompanyQuarters)Enum.Parse(ddlCompQuarter.SelectedValue);
You can use Enum.Parse
var val = (int)(ActiveQuarters)Enum.Parse(typeof(ActiveQuarters),
ddlCompQuarter.SelectedValue.ToString());
Also I think your code has problem, you defined ActiveQuarters enum and you bind CompanyQuarters!.
You have to reverse the way you got the names in there.
http://blogs.msdn.com/b/tims/archive/2004/04/02/106310.aspx
you need to use Enum.Parse and then you can get your enum from ComboBox
You have to set text and value property at time of binding the drop down.
For value field you can use
Enum.GetValues(typeof(EnumProvider.CompanyQuarters))

Categories