DropDown list with translated values - model-view-controller

I have enums in my domain like this
public enum AdTypeEnum { Sale = 1, Rent = 2, SaleOrRent = 3 };
In my view I'm rendering this enums like this
<div class="editor-field">
#Html.DropDownListFor(x => x.AdType, new SelectList(Enum.GetValues(typeof(MyDomain.Domain.Property.AdTypeEnum))))
</div>
Now, what I'm trying to achive is based on selected language I want to display these enums in drop down list in selected language.

Did you try something like:
public static Array Localize(Array values)
{
string[] result = new string[values.Length];
for (int i = 0; i < values.Length; ++i)
result[i] = Resources.ResourceManager.GetString(values.GetValue(i).ToString());
return result;
}
A better implementation should use a different key-set for each enum type (using the enum name as part of the GetString() parameter).
Anyway this method is pretty naive, I think for a big application (or for more complex scenarios) you may need to inherit from SelectList class.

Related

C#7: How to use tuples in generic methods (LINQ select example)

I have some heavily repeating code, which has always the same structure, just using different columns in a database for accessing it and doing similar stuff
A typical query looks like:
var portfolioIds = context.PortSelMotorSeries
.Select(x => new { x.Id, x.InstallationAltitudeMax })
.ToList();
Now I want to use a generic function for dependency inversion and to pass the selector function as a delegate to the query:
private void ForEachIterate<T1>(Func<MotorSeriesDb, T1> selectorFunc): where T1 : (int Id, double Value)
{
...
var portfolioIds = context.PortSelMotorSeries
.Select(selectorFunct)
.ToList();
...
}
So that I can call the query with my own selector:
ForEachIterate(x => new { Id = x.Id, Value = x.InstallationAltitudeMax });
ForEachIterate(x => new { Id = x.Id, Value = x.TemperatureMax });
Specifying the constraint with "where T1 : (int Id, double Value)" leads to a compiler error CS0701.
Leaving it away leads to other compiler errors.
Is there any way to use tuples in generic functions?
For one thing you're confusing tuples (the (int Id, double Value) thing) with anonymous classes (the new { Id = x.Id, Value = x.TemperatureMax }). They aren't even related, so your code would never work as is.
For another, if all you want is to force the user to output a tuple of some specific type, you can do something like this:
private void ForEachIterate(Func<MotorSeriesDb, (int, double)> selectorFunc)
{
...
var portfolioIds = context.PortSelMotorSeries
.Select(selectorFunct)
.ToList();
...
}
// call like:
ForEachIterate(x => (x.Id, x.InstallationAltitudeMax));
Note that there's nothing generic about your function at all. Which leads me to my third point: you're missing the entire point of Linq. You talk about inversion of control, but you're the one who's inverting it in the wrong direction to begin with.
You already have a construct that allows arbitrary selection: context.PortSelMotorSeries. Simply use Linq to select what you want out of it in the call site and you're done.
If you try this it could works:
private static void ForEachIterate<T1>(Func<MotorSeriesDb, T1> selectorFunc) where T1 : Tuple<int, double>
{
var portfolioIds = context.PortSelMotorSeries
.Select(selectorFunct)
.ToList();
}

Converting string to int, array of strings

I am having an issue with converting a string of id to an int when there are multiple strings passed in, the code shows the following:
for(int i = 0; i < Request.Params["service"].Length; i++)
{
int serviceID = int.Parse(Request.Params["service"]);
db.ServiceAssignments.Add(serviceAssignment);
serviceAssignment.locationID = locationID;
serviceAssignment.ServiceID = serviceID;
db.SaveChanges();
}
If you pass in one param, you get: int.Parse(Request.Params["Service"]); = 1, which then works and the database saves. however if you have the following you get:
'1,2' which three. What I want is 1 and then 2, not 1,2.
What is 1 and 2?
When you create anew location you get to select services for that location. The service id, in the case of this problem is 1 and 2. if I select one service then it saves and all is well. When I select two or more it doesnt work.
I though I could do:
Request.Params["Service"][i] because "Service" is an array after all. How ever this causes database problems and a whole other mess.
So what would you suggest I can do to make it save id 1 and id 2 when you select them for a location?
MVC 3 is quite powerful to figure out the binding, I don't know exactly what are you doing in the view that get the service Ids from user but I assume there is form there and if all Ids are int you can do like this and you don't need any conversion, or maybe you can use FormCollection. I don't think using Request in MVC 3 is a good idea, it does not really belong the whole MVC idea.
public void Add(int[] service)
{
foreach (var item in service)
{
int serviceID = item;
}
}
OR
public void Add(FormCollection frm)
{
foreach (var item in frm.AllKeys)
{
if (item.StartsWith("service"))
{
int serviceID = Int32.Parse(frm[item]);
}
}
}
anyway none of these are also MVC, these are should work but I recommend you to use Models in views and controllers
This will work. Just tested it:
string[] items = Request.Params["service"].Split(',');
for (int i = 0; i < items.Length; i++)
{
int serviceID = int.Parse(items[i]);
db.ServiceAssignments.Add(serviceAssignment);
serviceAssignment.locationID = locationID;
serviceAssignment.ServiceID = serviceID;
db.SaveChanges();
}
As a side note, I'd probably make two changes:
I'd use a foreach statement. No real difference; just less typing.
I'd put the SaveChanges() AFTER the for loop. This will make fewer calls to the database, but still accomplish the same thing.

MvcContrib Grid Sorting on complex object

I am trying to work with MvcContrib Grid control. But I cannot seem to get the sorting to work on complex objects that hold other objects.
I have setup my controller/classes/Views similar to the OP in this question.
Sorting with MVCContrib
I have tried to use the SortColumnName to my childobject.property but it gives me an error saying My main object does not have this property. This is my code snippet
//POCO class
class Issue {
public int ID {get; get; }
.....
public int priorityId {get; set;}
public virtual Priority priority {get; set;}
}
//Controller code
public ViewResult Index(int? pageNo, GridSortOptions sort)
{
var issues = db.issues.Include(i => i.priority);
ViewBag.sort = sort;
if (!string.IsNullOrEmpty(sort.Column))
{
issues = issues.OrderBy(sort.Column, sort.Direction);
}
return View(issues.ToList().AsPagination(pageNo ?? 1, 10));
}
//View code for the Grid
#Html.Grid(Model).Sort(ViewBag.sort as GridSortOptions).Columns(column => {
column.For(issue => Html.ActionLink(" ", "Edit", new { id = issue.ID, areas = "Issues", controller = "Main"}, new { #id="editBtn"})).Named("Edit");
column.For(issue => Html.ActionLink(issue.ID.ToString(), "Edit", new {id = issue.ID, areas = "Issues", controller = "Main"})).Named("ID").Sortable(true);
column.For(issue => issue.priority.codeDesc).Named("Priority").SortColumnName("priority.codeDesc").Sortable(true);
}).Empty("No data found")
When I try to sort on the priority string, it gives me an error saying 'priority.codeDesc is not a property of Issue'.
TIA
The issue here isn't actually related to the grid, but rather to the .OrderBy extension method provided as part of the MvcContrib sorting extensions. This extension is fairly simplistic and I only wrote it to cover simple cases where you want to sort on a direct property of the object, however in your case you're trying to order on a nested property ("priority.codeDesc") which isn't supported - you can't use dot notation with this extension.
You'd either need to switch to using a different mechanism to perform the actual sorting, or if this is a one-off situation then you could hard-code the sorting logic for this particular column (not ideal, but if it's a one off then it's simpler than writing a new sorting mechanism), eg:
if (!string.IsNullOrEmpty(sort.Column))
{
if(sort.Column == "priority.codeDesc")
{
issues = issues.OrderBy(x => x.priority.codeDesc);
}
else
{
issues = issues.OrderBy(sort.Column, sort.Direction);
}
}
OMG! Dots!
I was in the same boat but thanks God I found a brilliant solution posted by our fellow developer Jarrett Meyer. I found it after maybe 3 hours Googling in the past and just now when I decided to boost my pagination and sorting with MvcContrib Grid.
You can find the full post here:
Server-Side Sorting With Dynamic LINQ
His code saved me... :D The use of LINQ's Aggregate function was AWESOME! Kudozzz to him.
I had to change Jarretts' original code a little bit to fit it to my needs. Here's the code after I modified it:
public static IQueryable<T> OrderBy<T>(this IQueryable<T> collection, GridSortOptions sortOptions)
{
if (string.IsNullOrEmpty(sortOptions.Column))
{
return collection;
}
Type collectionType = typeof(T);
ParameterExpression parameterExpression = Expression.Parameter(collectionType, "p");
Expression seedExpression = parameterExpression;
Expression aggregateExpression = sortOptions.Column.Split('.').Aggregate(seedExpression, Expression.Property);
MemberExpression memberExpression = aggregateExpression as MemberExpression;
if (memberExpression == null)
{
throw new NullReferenceException(string.Format("Unable to cast Member Expression for given path: {0}.", sortOptions.Column));
}
LambdaExpression orderByExp = Expression.Lambda(memberExpression, parameterExpression);
const string orderBy = "OrderBy";
const string orderByDesc = "OrderByDescending";
Type childPropertyType = ((PropertyInfo)(memberExpression.Member)).PropertyType;
string methodToInvoke = sortOptions.Direction == MvcContrib.Sorting.SortDirection.Ascending ? orderBy : orderByDesc;
var orderByCall = Expression.Call(typeof(Queryable), methodToInvoke, new[] { collectionType, childPropertyType }, collection.Expression, Expression.Quote(orderByExp));
return collection.Provider.CreateQuery<T>(orderByCall);
}
Now you can call this extension method like this in your controller method:
var users = Database.Memberships.OrderBy(sort);
where sort is GridSortOptions that lives in MvcContrib.UI.Grid.
sort.ColumnName can contain strings like these ones now:
User.UserName
User.MyRelatedEntity.RelatedEntityProperty
User.MyRelatedEntity.RelatedEntityProperty.AndSoON
Note that when you create your Grid columns you can specify
.SortColumnName("User.UserName")

C# - Any clever way to get an int array from an object collection?

How can I create an easy helper method to get an int array from a collection of objects?
The idea would be have a method which receive a collection of "User" class:
public class User {
public int UserId {get;set;}
public string UserName {get;set;}
}
And filter this collection to get an int array of unique UserIds.
List<int> repeatedUserIds = (from item in list
select item.UserId).ToList();
List<int> uniqueUserIds = ((from n in repeatedUserIds
select n).Distinct()).ToList();
Is there a way to create a clever method for this purpose?
You could create an extension method:
public int[] GetUniqueIds<T>(this IEnumerable<T> items, Func<T, int> idSelector)
{
return items.Select(idSelector).Distinct().ToArray();
}
And use it like this:
int[] uniqueUserIds = list.GetUniqueIds(u => u.UserId);
Well, I wouldn't bother with a query expression, personally - but the rest is fine:
List<int> repeatedUserIds = list.Select(item => item.UserId)
.ToList();
List<int> uniqueUserIds = repeatedUserIds.Distinct()
.ToList();
If you don't need repeatedUserIds for anything else, don't bother with the intermediate call to ToList():
List<int> uniqueUserIds = list.Select(item => item.UserId)
.Distinct()
.ToList();
(I generally like putting each operation on a separate line, but of course you don't have to.)
Note that your text asks for an array, but your code has been in terms of List<int>. If you genuinely want an int[] instead of a List<int>, just change the ToList() calls to ToArray().
List<int> uniqueUserIds = (from n in list
select item.UserId).Distinct().ToList();

Umbraco DataTypes. Retrieve list of possible data types.

I have a property in umbraco that uses a drop down data type with a set of prevalues that you can select from.
How do I retrieve a list of all the possible prevalues that are in this drop down list?
There's a helper method in umbraco.library that does that.
From xslt:
<xsl:variable name="prevalues" select="umbraco.library:GetPreValues(1234)" />
From code:
using umbraco;
XPathNodeIterator prevalues = library.GetPrevalues(1234);
Replace 1234 with the id of your datatype (You can see it in the bottom of your browser when hovering your mouse over the datatype in the developers section)
Regards
Jesper Hauge
Here is the code that I use in one of my Umbraco datatypes to get a DropDownList containing all possible prevalues:
var prevalues = PreValues.GetPreValues(dataTypeDefinitionId);
DropDownList ddl = new DropDownList();
if (prevalues.Count > 0)
{
for (int i = 0; i < prevalues.Count; i++)
{
var prevalue = (PreValue)prevalues[i];
if (!String.IsNullOrEmpty(prevalue.Value))
{
ddl.Items.Add(new ListItem(prevalue.Value, prevalue.DataTypeId.ToString()));
}
}
}
Replace dataTypeDefinitionId with the id of your datatype.
I know this is an old question, but I created this method based on the information provided in this answer and I think it is worth documenting:
public static class UmbracoExtensions
{
public static IEnumerable<string> GetDropDownDataTypeValues(int dataTypeId)
{
var dataTypeValues = umbraco.library.GetPreValues(dataTypeId);
var dataTypeValuesEnumerator = dataTypeValues.GetEnumerator();
while (dataTypeValues.MoveNext())
{
dynamic dataTypeItem = dataTypeValues.Current;
yield return dataTypeItem.Value;
}
}
}

Resources