I am trying to bind a textfield to an object. I've done some research and I have found this answer.
public class Person {
String name;
String surname;
Address address;
// assume getters and setters
}
public class Address {
String street;
// assume getter and setters
}
Then, you could bind the street address like this:
Binder<Person> binder = new Binder<>();
TextField streetAddressField = new TextField();
// bind using lambda expressions
binder.bind(streetAddressField,
person -> person.getAddress().getStreet(),
(person, street) -> person.getAddress().setStreet(street));
What value do I instantiate street as (in the last line of code)?
The above was the example I found. My code is as follows - I have a contact class:
#Entity
public class Contact {
#Id
#GeneratedValue
private Long id;
private String firstName;
private String lastName;
private String phoneNumber;
#ManyToOne (cascade = {CascadeType.ALL})
#JoinColumn(name="phoneType_typeId")
private PhoneType phoneType;
public Contact(){
}
public Contact(String firstName, String lastName, String phoneNumber, PhoneType type) {
this.firstName = firstName;
this.lastName = lastName;
this.phoneNumber = phoneNumber;
this.phoneType = type;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public PhoneType getPhoneType() {
return phoneType;
}
public void setPhoneType(PhoneType phoneType) {
this.phoneType = phoneType;
}
#Override
public String toString() {
return String.format("Contact[firstName='%s', lastName='%s', phoneNumber='%s', phoneType = '%s']",
firstName, lastName, phoneNumber, phoneType);
}
}
Then I have a phoneType class:
#Entity
#Table(name="phoneType")
public class PhoneType {
#Id
#GeneratedValue
#Column(name = "typeId")
private Long id;
private String type;
public PhoneType(String type){
this.type = type;
}
public PhoneType(){}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
Then in a Contact Editor I am trying to bind the phoneType to a textfield:
#SpringComponent
#UIScope
public class ContactEditor extends VerticalLayout {
private final ContactRepository repository;
private Contact contact;
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
TextField phoneNumber = new TextField("Phone number");
TextField phoneType = new TextField( "Phone type");
Button save = new Button("Save", VaadinIcons.CHECK);
Button cancel = new Button("Cancel");
Button delete = new Button("Delete", VaadinIcons.TRASH);
CssLayout actions = new CssLayout(save, cancel, delete);
Binder<Contact> binder = new Binder<>(Contact.class);
#Autowired
public ContactEditor(ContactRepository repository, Contact contact) {
this.repository = repository;
this.contact = contact;
String type = contact.getPhoneType().getType();
addComponents(firstName, lastName, phoneNumber, phoneType, actions);
// bind using naming convention
**binder.bind(phoneType, contact.getPhoneType().getType(), contact.getPhoneType().setType(type));**
binder.bindInstanceFields(this);
// Configure and style components
setSpacing(true);
actions.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
save.setStyleName(ValoTheme.BUTTON_PRIMARY);
save.setClickShortcut(ShortcutAction.KeyCode.ENTER);
// wire action buttons to save, delete and reset
save.addClickListener(e -> repository.save(contact));
delete.addClickListener(e -> repository.delete(contact));
cancel.addClickListener(e -> editContact(contact));
setVisible(false);
}
public interface ChangeHandler {
void onChange();
}
public final void editContact(Contact c) {
if (c == null) {
setVisible(false);
return;
}
final boolean persisted = c.getId() != null;
if (persisted) {
// Find fresh entity for editing
contact = repository.findById(c.getId()).get();
}
else {
contact = c;
}
cancel.setVisible(persisted);
// Bind customer properties to similarly named fields
// Could also use annotation or "manual binding" or programmatically
// moving values from fields to entities before saving
binder.setBean(contact);
setVisible(true);
// A hack to ensure the whole form is visible
save.focus();
// Select all text in firstName field automatically
firstName.selectAll();
}
public void setChangeHandler(ChangeHandler h) {
// ChangeHandler is notified when either save or delete
// is clicked
save.addClickListener(e -> h.onChange());
delete.addClickListener(e -> h.onChange());
}
}
The line enclosed in ** in Contact Editor (i.e. binder.bind(phoneType, contact.getPhoneType().getType(), contact.getPhoneType().setType(type))) is giving me an error - "no instance of type variable FIELDVALUE exist so that string conforms to ValueProvider .
The line
binder.bind(phoneType, contact.getPhoneType().getType(), contact.getPhoneType().setType(type));
does not compile because the method arguments do not match to any of the bind methods, and there is an illegal Java expression in the 3rd argument. According to your question, you have simply forgotten to use lambdas. Try:
binder.bind(phoneType, c -> c.getPhoneType().getType(), (c, t) -> c.getPhoneType().setType(t));
Have a look at the method signature:
public <FIELDVALUE> Binder.Binding<BEAN,FIELDVALUE> bind(HasValue<FIELDVALUE> field,
ValueProvider<BEAN,FIELDVALUE> getter,
Setter<BEAN,FIELDVALUE> setter)
It expects ValueProvider and Setter as 2nd and 3rd argument. These interfaces have only one method to be implemented, therefore you can use lambdas to pass them to bind.
I don't know if this is what you'r asking, but what I see as missing is that you haven't binded your binder to any bean.
You have created the binder, and you've told your textfield which property is binded to, but now you need to tell the binder which is his bean.
Something like:
Person yourPerson = new Person(); //or get person from database somehow
yourPerson.setAddress(new Address());
yourPerson.getAddress().setStreet("Road cool code, 404");
binder.setBean(yourPerson);
This should do the trick... if not, please explain better what you need. ;)
I've got a property in my model called Promotion that its type is a flag enum called UserPromotion. Members of my enum have display attributes set as follows:
[Flags]
public enum UserPromotion
{
None = 0x0,
[Display(Name = "Send Job Offers By Mail")]
SendJobOffersByMail = 0x1,
[Display(Name = "Send Job Offers By Sms")]
SendJobOffersBySms = 0x2,
[Display(Name = "Send Other Stuff By Sms")]
SendPromotionalBySms = 0x4,
[Display(Name = "Send Other Stuff By Mail")]
SendPromotionalByMail = 0x8
}
Now I want to be able to create say a ul in my view to show the selected values of my Promotion property. This is what I have done so far but the problem is that how can I get the display names here?
<ul>
#foreach (int aPromotion in #Enum.GetValues(typeof(UserPromotion)))
{
var currentPromotion = (int)Model.JobSeeker.Promotion;
if ((currentPromotion & aPromotion) == aPromotion)
{
<li>Here I don't know how to get the display attribute of "currentPromotion".</li>
}
}
</ul>
One liner - Fluent syntax
public static class Extensions
{
/// <summary>
/// A generic extension method that aids in reflecting
/// and retrieving any attribute that is applied to an `Enum`.
/// </summary>
public static TAttribute GetAttribute<TAttribute>(this Enum enumValue)
where TAttribute : Attribute
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<TAttribute>();
}
}
Example
public enum Season
{
[Display(Name = "It's autumn")]
Autumn,
[Display(Name = "It's winter")]
Winter,
[Display(Name = "It's spring")]
Spring,
[Display(Name = "It's summer")]
Summer
}
public class Foo
{
public Season Season = Season.Summer;
public void DisplayName()
{
var seasonDisplayName = Season.GetAttribute<DisplayAttribute>();
Console.WriteLine("Which season is it?");
Console.WriteLine (seasonDisplayName.Name);
}
}
Output
Which season is it?
It's summer
UPDATE
First solution was focused on getting display names from enum. Code below should be exact solution for your problem.
You can use this helper class for enums:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
public static class EnumHelper<T>
where T : struct, Enum // This constraint requires C# 7.3 or later.
{
public static IList<T> GetValues(Enum value)
{
var enumValues = new List<T>();
foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
{
enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
}
return enumValues;
}
public static T Parse(string value)
{
return (T)Enum.Parse(typeof(T), value, true);
}
public static IList<string> GetNames(Enum value)
{
return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
}
public static IList<string> GetDisplayValues(Enum value)
{
return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
}
private static string lookupResource(Type resourceManagerProvider, string resourceKey)
{
var resourceKeyProperty = resourceManagerProvider.GetProperty(resourceKey,
BindingFlags.Static | BindingFlags.Public, null, typeof(string),
new Type[0], null);
if (resourceKeyProperty != null)
{
return (string)resourceKeyProperty.GetMethod.Invoke(null, null);
}
return resourceKey; // Fallback with the key name
}
public static string GetDisplayValue(T value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var descriptionAttributes = fieldInfo.GetCustomAttributes(
typeof(DisplayAttribute), false) as DisplayAttribute[];
if (descriptionAttributes[0].ResourceType != null)
return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);
if (descriptionAttributes == null) return string.Empty;
return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
}
}
And then you can use it in your view as following:
<ul>
#foreach (var value in #EnumHelper<UserPromotion>.GetValues(UserPromotion.None))
{
if (value == Model.JobSeeker.Promotion)
{
var description = EnumHelper<UserPromotion>.GetDisplayValue(value);
<li>#Html.DisplayFor(e => description )</li>
}
}
</ul>
Building on Aydin's great answer, here's an extension method that doesn't require any type parameters.
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
public static class EnumExtensions
{
public static string GetDisplayName(this Enum enumValue)
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.GetName();
}
}
NOTE: GetName() should be used instead of the Name property. This ensures that the localized string will be returned if using the ResourceType attribute property.
Example
To use it, just reference the enum value in your view.
#{
UserPromotion promo = UserPromotion.SendJobOffersByMail;
}
Promotion: #promo.GetDisplayName()
Output
Promotion: Send Job Offers By Mail
Based on Aydin's answer I would suggest a less "duplicatious" implementation (because we could easily get the Type from the Enum value itself, instead of providing it as a parameter 馃槈:
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
public static string GetDisplayName(this Enum enumValue)
{
return enumValue.GetType().GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.Name;
}
EDIT (based upon #Vahagn Nahapetyan's comment)
public static string GetDisplayName(this Enum enumValue)
{
return enumValue.GetType()?
.GetMember(enumValue.ToString())?
.First()?
.GetCustomAttribute<DisplayAttribute>()?
.Name;
}
Now we can use it very clean in this way:
public enum Season
{
[Display(Name = "The Autumn")]
Autumn,
[Display(Name = "The Weather")]
Winter,
[Display(Name = "The Tease")]
Spring,
[Display(Name = "The Dream")]
Summer
}
Season.Summer.GetDisplayName();
Which results in
"The Dream"
If you are using MVC 5.1 or upper there is simplier and clearer way: just use data annotation (from System.ComponentModel.DataAnnotations namespace) like below:
public enum Color
{
[Display(Name = "Dark red")]
DarkRed,
[Display(Name = "Very dark red")]
VeryDarkRed,
[Display(Name = "Red or just black?")]
ReallyDarkRed
}
And in view, just put it into proper html helper:
#Html.EnumDropDownListFor(model => model.Color)
Building on Todd's great answer which built on Aydin's great answer, here's a generic extension method which doesn't require any type parameters.
/// <summary>
/// Gets human-readable version of enum.
/// </summary>
/// <returns>effective DisplayAttribute.Name of given enum.</returns>
public static string GetDisplayName<T>(this T enumValue) where T : IComparable, IFormattable, IConvertible // C# 7.3+: where T : struct, Enum
{
if (!typeof(T).IsEnum) // Not needed in C# 7.3+ with above updated constraint
throw new ArgumentException("Argument must be of type Enum");
DisplayAttribute displayAttribute = enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
string displayName = displayAttribute?.GetName();
return displayName ?? enumValue.ToString();
}
I needed this for my project because something like the below code, where not every member of the enum has a DisplayAttribute, throws an exception with Todd's solution:
public class MyClass
{
public enum MyEnum
{
[Display(Name="ONE")]
One,
// No DisplayAttribute
Two
}
public void UseMyEnum()
{
MyEnum foo = MyEnum.One;
MyEnum bar = MyEnum.Two;
Console.WriteLine(foo.GetDisplayName());
Console.WriteLine(bar.GetDisplayName());
}
}
// Output:
//
// ONE
// Two
If this is a complicated solution to a simple problem, please let me know, but this was the fix I used.
You could use Type.GetMember Method, then get the attribute info using reflection:
// display attribute of "currentPromotion"
var type = typeof(UserPromotion);
var memberInfo = type.GetMember(currentPromotion.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var description = ((DisplayAttribute)attributes[0]).Name;
There were a few similar posts here:
Getting attributes of Enum's value
How to make MVC3 DisplayFor show the value of an Enum's Display-Attribute?
In .NET5, I used DisplayTextFor without needing helper or extension methods:
#Html.DisplayTextFor(m => m.SomeEnumProperty)
Where SomeEnumProperty has a value of:
public enum MyEnum
{
[Display(Name = "Not started")]
NotStarted = 0,
[Display(Name = "Weird display name instead of just 'Started'")]
Started = 1,
}
For ASP.Net Core 3.0, this worked for me (credit to previous answerers).
My Enum class:
using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
public class Enums
{
public enum Duration
{
[Display(Name = "1 Hour")]
OneHour,
[Display(Name = "1 Day")]
OneDay
}
// Helper method to display the name of the enum values.
public static string GetDisplayName(Enum value)
{
return value.GetType()?
.GetMember(value.ToString())?.First()?
.GetCustomAttribute<DisplayAttribute>()?
.Name;
}
}
My View Model Class:
public class MyViewModel
{
public Duration Duration { get; set; }
}
An example of a razor view displaying a label and a drop-down list. Notice the drop-down list does not require a helper method:
#model IEnumerable<MyViewModel>
#foreach (var item in Model)
{
<label asp-for="#item.Duration">#Enums.GetDisplayName(item.Duration)</label>
<div class="form-group">
<label asp-for="#item.Duration" class="control-label">Select Duration</label>
<select asp-for="#item.Duration" class="form-control"
asp-items="Html.GetEnumSelectList<Enums.Duration>()">
</select>
</div>
}
With Core 2.1,
public static string GetDisplayName(Enum enumValue)
{
return enumValue.GetType()?
.GetMember(enumValue.ToString())?[0]?
.GetCustomAttribute<DisplayAttribute>()?
.Name;
}
<ul>
#foreach (int aPromotion in #Enum.GetValues(typeof(UserPromotion)))
{
var currentPromotion = (int)Model.JobSeeker.Promotion;
if ((currentPromotion & aPromotion) == aPromotion)
{
<li>#Html.DisplayFor(e => currentPromotion)</li>
}
}
</ul>
combining all edge-cases together from above:
enum members with base object members' names (Equals, ToString)
optional Display attribute
here is my code:
public enum Enum
{
[Display(Name = "What a weird name!")]
ToString,
Equals
}
public static class EnumHelpers
{
public static string GetDisplayName(this Enum enumValue)
{
var enumType = enumValue.GetType();
return enumType
.GetMember(enumValue.ToString())
.Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == enumType)
.First()
.GetCustomAttribute<DisplayAttribute>()?.Name ?? enumValue.ToString();
}
}
void Main()
{
Assert.Equals("What a weird name!", Enum.ToString.GetDisplayName());
Assert.Equals("Equals", Enum.Equals.GetDisplayName());
}
You need to use a bit of reflection in order to access that attribute:
var type = typeof(UserPromotion);
var member = type.GetMember(Model.JobSeeker.Promotion.ToString());
var attributes = member[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var name = ((DisplayAttribute)attributes[0]).Name;
I recommend wrapping this method in a extension method or perform this in a view model.
I'm sorry to do this, but I couldn't use any of the other answers as-is and haven't time to duke it out in the comments.
Uses C# 6 syntax.
static class EnumExtensions
{
/// returns the localized Name, if a [Display(Name="Localised Name")] attribute is applied to the enum member
/// returns null if there isnt an attribute
public static string DisplayNameOrEnumName(this Enum value)
// => value.DisplayNameOrDefault() ?? value.ToString()
{
// More efficient form of ^ based on http://stackoverflow.com/a/17034624/11635
var enumType = value.GetType();
var enumMemberName = Enum.GetName(enumType, value);
return enumType
.GetEnumMemberAttribute<DisplayAttribute>(enumMemberName)
?.GetName() // Potentially localized
?? enumMemberName; // Or fall back to the enum name
}
/// returns the localized Name, if a [Display] attribute is applied to the enum member
/// returns null if there is no attribute
public static string DisplayNameOrDefault(this Enum value) =>
value.GetEnumMemberAttribute<DisplayAttribute>()?.GetName();
static TAttribute GetEnumMemberAttribute<TAttribute>(this Enum value) where TAttribute : Attribute =>
value.GetType().GetEnumMemberAttribute<TAttribute>(value.ToString());
static TAttribute GetEnumMemberAttribute<TAttribute>(this Type enumType, string enumMemberName) where TAttribute : Attribute =>
enumType.GetMember(enumMemberName).Single().GetCustomAttribute<TAttribute>();
}
Building further on Aydin's and Todd's answers, here is an extension method that also lets you get the name from a resource file
using AppResources;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Resources;
public static class EnumExtensions
{
public static string GetDisplayName(this Enum enumValue)
{
var enumMember= enumValue.GetType()
.GetMember(enumValue.ToString());
DisplayAttribute displayAttrib = null;
if (enumMember.Any()) {
displayAttrib = enumMember
.First()
.GetCustomAttribute<DisplayAttribute>();
}
string name = null;
Type resource = null;
if (displayAttrib != null)
{
name = displayAttrib.Name;
resource = displayAttrib.ResourceType;
}
return String.IsNullOrEmpty(name) ? enumValue.ToString()
: resource == null ? name
: new ResourceManager(resource).GetString(name);
}
}
and use it like
public enum Season
{
[Display(ResourceType = typeof(Resource), Name = Season_Summer")]
Summer
}
For just displaying enum's display name attribute just use
Microsoft.AspNetCore.Mvc.Rendering's
#Html.DisplayFor(x => EnumType.EnumValue)
That's would be enough.
For displaying SelectList write as following:
<select id="someIdForTheEndPoint" asp-items="Html.GetEnumSelectList<EnumType>()">
<option selected="selected" value="">Select value</option>
</select>
I have two solutions for this Question.
The first solution is on getting display names from enum.
public enum CourseLocationTypes
{
[Display(Name = "On Campus")]
OnCampus,
[Display(Name = "Online")]
Online,
[Display(Name = "Both")]
Both
}
public static string DisplayName(this Enum value)
{
Type enumType = value.GetType();
string enumValue = Enum.GetName(enumType, value);
MemberInfo member = enumType.GetMember(enumValue)[0];
object[] attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
string outString = ((DisplayAttribute)attrs[0]).Name;
if (((DisplayAttribute)attrs[0]).ResourceType != null)
{
outString = ((DisplayAttribute)attrs[0]).GetName();
}
return outString;
}
<h3 class="product-title white">#Model.CourseLocationType.DisplayName()</h3>
The second Solution is on getting display name from enum name but that will be enum split in developer language it's called patch.
public static string SplitOnCapitals(this string text)
{
var r = new Regex(#"
(?<=[A-Z])(?=[A-Z][a-z]) |
(?<=[^A-Z])(?=[A-Z]) |
(?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
return r.Replace(text, " ");
}
<div class="widget-box pt-0">
#foreach (var item in Enum.GetNames(typeof(CourseLocationType)))
{
<label class="pr-2 pt-1">
#Html.RadioButtonFor(x => x.CourseLocationType, item, new { type = "radio", #class = "iCheckBox control-label" }) #item.SplitOnCapitals()
</label>
}
#Html.ValidationMessageFor(x => x.CourseLocationType)
</div>
2020 Update: An updated version of the function provided by many in this thread but now for C# 7.3 onwards:
Now you can restrict generic methods to enums types so you can write a single method extension to use it with all your enums like this:
The generic extension method:
public static string ATexto<T>(this T enumeraci贸n) where T : struct, Enum {
var tipo = enumeraci贸n.GetType();
return tipo.GetMember(enumeraci贸n.ToString())
.Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo).First()
.GetCustomAttribute<DisplayAttribute>()?.Name ?? enumeraci贸n.ToString();
}
The enum:
public enum TipoImpuesto {
IVA, INC, [Display(Name = "IVA e INC")]IVAeINC, [Display(Name = "No aplica")]NoAplica };
How to use it:
var tipoImpuesto = TipoImpuesto.IVAeINC;
var textoTipoImpuesto = tipoImpuesto.ATexto(); // Prints "IVA e INC".
Bonus, Enums with Flags: If you are dealing with normal enums the function above is enough, but if any of your enums can take multiple values with the use of flags then you will need to modify it like this (This code uses C#8 features):
public static string ATexto<T>(this T enumeraci贸n) where T : struct, Enum {
var tipo = enumeraci贸n.GetType();
var textoDirecto = enumeraci贸n.ToString();
string obtenerTexto(string textoDirecto) => tipo.GetMember(textoDirecto)
.Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo)
.First().GetCustomAttribute<DisplayAttribute>()?.Name ?? textoDirecto;
if (textoDirecto.Contains(", ")) {
var texto = new StringBuilder();
foreach (var textoDirectoAux in textoDirecto.Split(", ")) {
texto.Append($"{obtenerTexto(textoDirectoAux)}, ");
}
return texto.ToString()[0..^2];
} else {
return obtenerTexto(textoDirecto);
}
}
The enum with flags:
[Flags] public enum TipoContribuyente {
[Display(Name = "Com煤n")] Com煤n = 1,
[Display(Name = "Gran Contribuyente")] GranContribuyente = 2,
Autorretenedor = 4,
[Display(Name = "Retenedor de IVA")] RetenedorIVA = 8,
[Display(Name = "R茅gimen Simple")] R茅gimenSimple = 16 }
How to use it:
var tipoContribuyente = TipoContribuyente.RetenedorIVA | TipoContribuyente.GranContribuyente;
var textoAux = tipoContribuyente.ATexto(); // Prints "Gran Contribuyente, Retenedor de IVA".
I want to contribute with culture-dependent GetDisplayName enum extension. Hope this will be usefull for anyone googling this answer like me previously:
"standart" way as Aydin Adn and Todd mentioned:
public static string GetDisplayName(this Enum enumValue)
{
return enumValue
.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.GetName();
}
"Culture-dependent" way:
public static string GetDisplayName(this Enum enumValue, CultureInfo ci)
{
var displayAttr = enumValue
.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
var resMan = displayAttr.ResourceType?.GetProperty(#"ResourceManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as ResourceManager;
return resMan?.GetString(displayAttr.Name, ci) ?? displayAttr.GetName();
}
It is maybe cheating, but it's works:
#foreach (var yourEnum in Html.GetEnumSelectList<YourEnum>())
{
#yourEnum.Text
}
Based on previous answers I've created this comfortable helper to support all DisplayAttribute properties in a readable way:
public static class EnumExtensions
{
public static DisplayAttributeValues GetDisplayAttributeValues(this Enum enumValue)
{
var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute<DisplayAttribute>();
return new DisplayAttributeValues(enumValue, displayAttribute);
}
public sealed class DisplayAttributeValues
{
private readonly Enum enumValue;
private readonly DisplayAttribute displayAttribute;
public DisplayAttributeValues(Enum enumValue, DisplayAttribute displayAttribute)
{
this.enumValue = enumValue;
this.displayAttribute = displayAttribute;
}
public bool? AutoGenerateField => this.displayAttribute?.GetAutoGenerateField();
public bool? AutoGenerateFilter => this.displayAttribute?.GetAutoGenerateFilter();
public int? Order => this.displayAttribute?.GetOrder();
public string Description => this.displayAttribute != null ? this.displayAttribute.GetDescription() : string.Empty;
public string GroupName => this.displayAttribute != null ? this.displayAttribute.GetGroupName() : string.Empty;
public string Name => this.displayAttribute != null ? this.displayAttribute.GetName() : this.enumValue.ToString();
public string Prompt => this.displayAttribute != null ? this.displayAttribute.GetPrompt() : string.Empty;
public string ShortName => this.displayAttribute != null ? this.displayAttribute.GetShortName() : this.enumValue.ToString();
}
}
I tried doing this as an edit but it was rejected; I can't see why.
The above will throw an exception if you call it with an Enum that has a mix of custom attributes and plain items, e.g.
public enum CommentType
{
All = 1,
Rent = 2,
Insurance = 3,
[Display(Name="Service Charge")]
ServiceCharge = 4
}
So I've modified the code ever so slightly to check for custom attributes before trying to access them, and use the name if none are found.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
public static class EnumHelper<T>
{
public static IList<T> GetValues(Enum value)
{
var enumValues = new List<T>();
foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
{
enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
}
return enumValues;
}
public static T Parse(string value)
{
return (T)Enum.Parse(typeof(T), value, true);
}
public static IList<string> GetNames(Enum value)
{
return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
}
public static IList<string> GetDisplayValues(Enum value)
{
return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
}
private static string lookupResource(Type resourceManagerProvider, string resourceKey)
{
foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
{
System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
return resourceManager.GetString(resourceKey);
}
}
return resourceKey; // Fallback with the key name
}
public static string GetDisplayValue(T value)
{
var fieldInfo = value.GetType().GetField(value.ToString());
var descriptionAttributes = fieldInfo.GetCustomAttributes(
typeof(DisplayAttribute), false) as DisplayAttribute[];
if (descriptionAttributes.Any() && descriptionAttributes[0].ResourceType != null)
return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);
if (descriptionAttributes == null) return string.Empty;
return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
}
}
Using MVC5 you could use:
public enum UserPromotion
{
None = 0x0,
[Display(Name = "Send Job Offers By Mail")]
SendJobOffersByMail = 0x1,
[Display(Name = "Send Job Offers By Sms")]
SendJobOffersBySms = 0x2,
[Display(Name = "Send Other Stuff By Sms")]
SendPromotionalBySms = 0x4,
[Display(Name = "Send Other Stuff By Mail")]
SendPromotionalByMail = 0x8
}
then if you want to create a dropdown selector you can use:
#Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select")
assume that your enum name is OrderState, Use this code:
#Html.DropDownList("selectList", new SelectList(Html.GetEnumSelectList<OrderState>(), "Value", "Text",ViewBag.selectedOrderState), new {#id="OrderState", #class = "form-control" })
and set selected option in backend:
var selectedOrderState = ..Data.OrderState.GetHashCode();
ViewBag.selectedOrderState = selectedOrderState;
I have been given the painful task of writing a C# application to sync up employee time entries in a separate database with Quickbooks. Since I'm brand new to QB programming, I'm trying to peform basic tasks, such as getting a list of customers, then jobs for each customer, then employees. I've been reading the SDK documentation, but I'm still a little fuzzy on the details because the examples I'm finding are a little too advanced for me at the moment :-P
To keep things simple, I would like to ask for a code snippet that gives me the list of customers for starters. Here's the code I've got:
QBSessionManager SessionManager = new QBSessionManager();
IMsgSetRequest customerSet = SessionManager.CreateMsgSetRequest("US", 8, 0);
//
// Code to get list of customers here.
//
SessionManager.OpenConnection2("", "New App", ENConnectionType.ctLocalQBD);
SessionManager.BeginSession(string.Empty, ENOpenMode.omDontCare);
IMsgSetResponse Resp = SessionManager.DoRequests(customerSet);
MessageBox.Show(Resp.ToXMLString());
SessionManager.EndSession();
SessionManager.CloseConnection();
Can anyone fill in the "code to get list of customers here" for me? Thank you very much in advance!
Victor
customers.IncludeRetElementList.Add("IsActive");
customers.IncludeRetElementList.Add("ListID");
customers.IncludeRetElementList.Add("EditSequence");
customers.IncludeRetElementList.Add("Name");
customers.IncludeRetElementList.Add("ParentRef");
Only the fields specified in the above list will be returned from QuickBooks - it is very important to use the correct strings in the correct case - no error messages will result if something is wrong. You cannot specify sub-fields (eg, City within an Address block; you must get the entire Address block). For custom fields, you also must specify the OwnerID (use 0 for custom fields that are not private to an application)
customers.IncludeRetElementList.Add("DataExtRet"); //will return non-private and/or private data extension fields depending on the OwnerIDList, below
customers.OwnerIDList.Add("0"); // required for non-private data extn fields
customers.OwnerIDList.Add("Your Appln GUID"); // Use this to get private data extns for the Appln identified by the GUID
Ok, seems like I found the missing piece:
ICustomerQuery customers = customerSet.AppendCustomerQueryRq();
This produces all the data related to each customer, which is a step forward. Parsing the XML for customers should be pretty straightforward, but parsing the individual tasks/jobs for each customer will be laborious, because there are no subnodes for each task - basically you get repeating chunks of XML with all the basic customer info (address, billing address, shipping address, etc.), then this one property called "FullName" which appends a colon to the customer name, followed by the task title (which itself can be followed by another colon with a subtask title, etc.). I'm wondering if there's something clever I can do with the request query to get a better xml response (for instance, specify what properties I want returned, and maybe enforce the creation of subnodes for each task for a given customer)...comments are appreciated.
Adding to Victors, Chili and Hassan's answer. Glad to have stumbled on this question as I myself was struggling with the QBFC examples.
Here is a full set of code that might just help someone down the road. If in the meantime someone could just point me in the direction of some useful documentation...that would be great.
Getting the Employee data to an XML string
public static string EmployeeListXML()
{
QBSessionManager SessionManager = new QBSessionManager();
IMsgSetRequest msgSetReq = SessionManager.CreateMsgSetRequest("US", 8, 0);
IEmployeeQuery employee = msgSetReq.AppendEmployeeQueryRq();
employee.IncludeRetElementList.Add("IsActive");
employee.IncludeRetElementList.Add("ListID");
employee.IncludeRetElementList.Add("EditSequence");
employee.IncludeRetElementList.Add("FirstName");
employee.IncludeRetElementList.Add("LastName");
employee.IncludeRetElementList.Add("SSN");
//employee.IncludeRetElementList.Add("ParentRef");
//employee.IncludeRetElementList.Add("DataExtRet"); //will return non-private and/or private data extension fields depending on the OwnerIDList, below
employee.OwnerIDList.Add("0"); // required for non-private data extn fields
//customers.OwnerIDList.Add("Your Appln GUID"); // Use this to get private data extns for the Appln identified by the GUID
SessionManager.OpenConnection2("", Application.ProductName, ENConnectionType.ctLocalQBD);
//SessionManager.BeginSession(string.Empty, ENOpenMode.omDontCare);
SessionManager.BeginSession(frmMain.QBFileName, ENOpenMode.omDontCare); // I have the filename on frmMain
IMsgSetResponse Resp = SessionManager.DoRequests(msgSetReq);
SessionManager.EndSession();
SessionManager.CloseConnection();
//MessageBox.Show(Resp.ToXMLString());
return Resp.ToXMLString();
}
Putting the XML string into a List of Emplpoyee Objects
public static List<Employee> EmployeeXMLtoList()
{
string sXML = EmployeeListXML();
List<Employee> lstEmp = new List<Employee>();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(sXML);
XmlNodeList parentNode = xmlDoc.GetElementsByTagName("EmployeeRet");
foreach (XmlNode childNode in parentNode)
{
Employee oEmp = new Employee();
oEmp.ListID = childNode.SelectSingleNode("ListID").InnerText;
oEmp.EditSequence = childNode.SelectSingleNode("EditSequence").InnerText;
oEmp.Active = childNode.SelectSingleNode("IsActive").InnerText;
oEmp.FirstName = childNode.SelectSingleNode("FirstName").InnerText;
oEmp.LastName = childNode.SelectSingleNode("LastName").InnerText;
oEmp.SSN = childNode.SelectSingleNode("SSN").InnerText;
lstEmp.Add(oEmp);
}
return lstEmp;
}
Function that return an Employee Object using Linq
public static Employee GetEmployeeObject(string sSSN)
{
Employee oReturn = null;
List<Employee> lstEmployee = EmployeeXMLtoList();
IEnumerable<Employee> lstEmps = from oEmp in lstEmployee
where oEmp.SSN == sSSN
select oEmp;
foreach (var oEmp in lstEmps)
{
oReturn = oEmp;
}
return oReturn;
}
Example of Code
Employee oEmployee = QB.GetEmployeeObject("112-35-8560");
Employee Class
public class Employee
{
private string sEmployeeID;
private string sSSN;
private string sLastName;
private string sFirstName;
private string sAddress1;
private string sAddress2;
private string sCity;
private string sState;
private string sZipCode;
private string sGender;
private string sEthnicity;
private DateTime dDOB;
private string sMaritalStatus;
private int iDependants;
private string sUScitizen;
private decimal iPayRate;
private string sPhone;
private DateTime dHireDate;
private string sEmail;
public Employee() { }
public string EmployeeID
{
get { return sEmployeeID; }
set { sEmployeeID = value; }
}
public string ListID
{
get; set;
}
public string EditSequence
{
get; set;
}
public string Active
{
get; set;
}
public string SSN
{
get { return sSSN; }
set { sSSN = value; }
}
public string LastName
{
get { return sLastName; }
set { sLastName = value; }
}
public string FirstName
{
get { return sFirstName; }
set { sFirstName = value; }
}
public string FullName
{
get { return FirstName + " " + LastName; }
set { }
}
public string Address1
{
get { return sAddress1; }
set { sAddress1 = value; }
}
public string Address2
{
get { return sAddress2; }
set { sAddress2 = value; }
}
public string State
{
get { return sState; }
set { sState = value; }
}
public string City
{
get { return sCity; }
set { sCity = value; }
}
public string ZipCode
{
get { return sZipCode; }
set { sZipCode = value; }
}
public string Gender
{
get { return sGender; }
set { sGender = value; }
}
public string Ethnicity
{
get { return sEthnicity; }
set { sEthnicity = value; }
}
public DateTime DOB
{
get { return dDOB; }
set { dDOB = value; }
}
public string MaritalStatus
{
get { return sMaritalStatus; }
set { sMaritalStatus = value; }
}
public int Dependants
{
get { return iDependants; }
set { iDependants = value; }
}
public string UScitizen
{
get { return sUScitizen; }
set { sUScitizen = value; }
}
public decimal PayRate
{
get { return iPayRate; }
set { iPayRate = value; }
}
public DateTime HireDate
{
get { return dHireDate; }
set { dHireDate = value; }
}
public string Phone
{
get { return sPhone; }
set { sPhone = value; }
}
public string Email
{
get { return sEmail; }
set { sEmail = value; }
}
}