In a document library I need a custom calculated column, because the default Excel formula don't provide the functionality I need.
I created a custom field inheriting from SPFieldText, that I then could customize at will. The question is: how is it possible, from my custom field, to access the content values of the other fields of the document library?
In other world, in the overriden GetValidatedString method, how can I return a value that is dependent upon values from other fields, for the same record? How to implement getFieldValue() , below:
public class MyCustomField : SPFieldText
{
....
public override string GetValidatedString(object value)
{
string value1 = getFieldValue("Column-Name1");
string value2 = getFieldValue("Column-Name2");
return value1 + ", " + value2; // any arbitrary operation on field values
}
}
Thanks!
You should be able to grab other values from the form using the Item property of the FormComponent or the Item property of the ItemContext.
Either of these should work from the FieldControl class:
Code Snippet
if ((this.ControlMode == SPControlMode.New) || (this.ControlMode == SPControlMode.Edit))
{
object obj = this.Item["Name"];
if (obj != null)
string name = obj.ToString();
object obj2 = base.ItemContext.Item["Name"];
if (obj2 != null)
string name2 = obj2.ToString();
}
where "Name" is the internal name of the field that you wish to retrieve.
Related
In order to map Hibernate query result to a custom class containing an enum, I should do like this according to this post but I don't want to use enum field name but one of its multiple values :
Properties params = new Properties();
params.put("enumClass", "MyStatusEnum");
params.put("useNamed", true)
String sql = "SELECT "
+ "PRICE as price, "
+ "COMPANY as companyId, "
+ "NAME as name, "
+ "STATUS as statusEnum "
+ "FROM `FUC**** TABLE WITH SPACE`";
List <Item> items = session.createNativeQuert(sql) // Obliged to use this method
// with deprecated transformer after because createQuery does not
// recognize ` escape character and if I use session.createQuery(sql, Item.class),
// Item is not recognized as an entity ...
.addScalar(price) // Obliged to do it for all fields just because I need to do it for one field ?!
.addScalar(companyId)
.addScalar(name)
.addScalar(statusEnum)
.setResultTransformer(Transformers.aliasToBean(Item.class)).list();
1) The problem is for MyEnum.AVAILABLE for example, data will not be "available" but an int so this is my enum :
public enum MyEnum {
AVAILABLE(0, 1),
TO_SENT(1, null),
ARCHIVED(2, null);
private final int stateNum;
private final Integer nextStateNum;
MyEnum(int stateNum, Integer nextStateNum) {
this.stateNum = stateNum;
this.nextStateNum = nextStateNum;
}
}
And I want to map the STATUS (possible values : 0, 1, 2) in DB not to the name but to the first attribute code (stateNum), how to do that ? Coul I apply a function to get enum from code ?
Properties params = new Properties();
params.put("enumClass", "Foo.ProfileStateEnum");
params.put("???", "???");
2) How to get doc about properties mapping to enum and that for hibernate < 5, we must use params.put("type", "12");, where is corresponding doc ?
Thank you very much,
Answer to 1) : Mapping Enum Types with Hibernate Example is a track I'm testing but I would not use annotation but code.
Answer to 2) : Class EnumType
So I have an arraylist basket that stores items, each item is made out of the name of the item and the price of the item fields.
As you can see there's two sugar with same price.
I want my code to print every single item with the amount of time its repeated.
What I want it to do is this:
Count the duplicate values
2 x Sugar for 100
1 x Cake for 75
1 x Salt for 30
1 x Fanta for 50
My Item class toString's method is
public String toString(){
return name + " for " + price;
}
basket = new ArrayList<Item>();
basket.add(new Item("Sugar", 100));
basket.add(new Item("Sugar", 100));
basket.add(new Item("Cake", 75));
basket.add(new Item("Salt", 30));
basket.add(new Item("Fanta", 50));
HashSet<Item> set = new Hashset(basket)
for (Item item : set ){
System.out.println(Collections.frequency(basket, item) + " x" + item);
}
But what it does is...
1 x Sugar for 100
1 x Sugar for 100
1 x Cake for 75
1 x Salt for 30
1 x Fanta for 50
so i'm thinking that its comparing the toStrings but the repeated ones are not equalling to true.
please help.
This is my first ever post and don't really know the exact rules of posting
It would be better to use a Map in this scenario. First, make sure you are implementing the equals(Object) and hashCode() methods in your Item object, then putting each unique Item into the map with a value of an AtomicInteger with base value 1. Before putting in the object in the map you should check to make sure the item is not already in the map, if it already exists in the map, get the AtomicInteger and increment it.
Something like this..
Map<Item, AtomicInteger> quantitiesByItem = new HashMap<>();
for (Item item : listOfItems) {
if (!quantitiesByItem.contains(item)) {
quantitiesByItem.put(item, new AtomicInteger(1));
} else {
quantitiesByItem.get(item).incrementAndGet();
}
}
A HashSet actually prevents duplicates so would only be useful in a scenario where you are trying to strip duplicate records.
EDIT: You could also use Collections.frequency but you need to implement equals(Object) and hashCode() in your Item object otherwise the objects are determined to be different because they aren't the exact same object. You will also need to stop adding all your values from your list to a set and instead just pass your List object to Collections.frequency method.
This is what my code was missing in my Item class;
You need to override the equals and hashcode methods that every objects have by default. This will allow you to compare two objects by their state.
object A with to private fields e.g. int field and a String field
with object B. If both fields are the same there return value will be true
#Override
public boolean equals(Object obj){
//check for null
if(this == null){
return false;
}
//make sure obj is a item
if(getClass() != obj.getClass()){
return false;
}
//cast obj as an item
final Item passsedItem = (Item) obj;
//check fields
if(!Objects.equals(this.name, passsedItem.name)){
return false;
}
if(!Objects.equals(this.price, passsedItem.price)){
return false;
}
return true;
}
/**
* Override hashcode method to be able to compare item state to see if they are the same
* #return
*/
#Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Objects.hashCode(this.price);
return hash;
}
in asp.net mvc 4, I write a custom Exception handler, working as a Attribute named HandleCustomError.
In this handler, I should know which action the current request for, then I can know what kind of return type for this action. I will return different data for "return type view() and json".
But, now I have two action with the same name, but one is for "Get", other is for "Post".The method "GetMethod" return an error: " System.Reflection.AmbiguousMatchException "
public class HandleCustomError : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
//base.OnException(filterContext);
if (filterContext.ExceptionHandled)
{
return;
}
else
{
//Determine the return type of the action
string actionName = filterContext.RouteData.Values["action"].ToString();
Type controllerType = filterContext.Controller.GetType();
var method = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var returnType = method.ReturnType;
}
....(Omitted)
I also came across this issue that below line was giving Ambigeous issue
controllerType.GetMethod(actionName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance);
Reason was that controller has two method with same name one is
[HTTPGET]
and other iis
[HTTPPOST]
.
For to get exact method I use GetMethods and LINQ.
Note: In controller writting [HTTPGet]**on action is not compulsory for get method i.e. on action if HTTpGet is not written the by default .net will consider it as **[HttpGet]. But for post action it is compulsory.
Will use this property for finding the correct method.
Steps
1. Find Type of request
2. Find the action using reflection
Finding Request type:
var actionName =
filterContext.RouteData.Values["action"].ToString();
Type typeOfRequest = filterContext.HttpContext.Request.RequestType.ToLower()
=="get"?typeof(HttpGetAttribute):typeof(HttpPostAttribute);
Finding method:
var cntMethods = controllerType.GetMethods()
.Where(m =>
m.Name == actionName &&
( ( typeOfRequest == typeof(HttpPostAttribute) &&
m.CustomAttributes.Where(a => a.AttributeType == typeOfRequest).Count()>0
)
||
( typeOfRequest == typeof(HttpGetAttribute) &&
m.CustomAttributes.Where(a => a.AttributeType == typeof(HttpPostAttribute)).Count() == 0
)
)
);
MethodInfo actionMethodInfo = actionMethodInfo = cntMethods != null && cntMethods.Count() == 1 ? cntMethods.ElementAt(0):null;
Reference : https://techatfingers.wordpress.com/2016/06/14/session-state-on-action/
As you have mentioned that you have two action with the same name, but one is for "Get", other is for "Post" , You could try out the [HttpGet] to the first action and [HttpPost] to the section action or you can try something like this if your action serves requests from multiple verbs
[HttpGet, HttpPost] or [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
For Example ,
if your function name is GetMethod then try like this
[HttpGet]
Public ActionResult GetMethod()
{
//do something ...
}
[HttpPost]
Public ActionResult GetMethod()
{
//do something ...
}
One approach to solve this issue is to use the GetMethods() method on the System.Type object to return a list of methods on the System.Type object. Use a LINQ query to filter the method list to just those methods that match a specific action name.
Add this approach by replacing the following in your code:
var method = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
with the following if condition that checks if multiple methods are found that match the variable actionName from your code. Define a string variable that identifies the action type (i.e. "HttpGet" or "HttpPost") and compare it to the attributes of each method in the filtered list.
System.Reflection.MethodInfo[] matchedMethods = controllerType.GetMethods(
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
.Where(m => m.Name == actionName).ToArray<System.Reflection.MethodInfo>();
if (matchedMethods.Length > 1)
{
string attributeTypeString = "HttpGet"; // Change this to "HttpPut" or the text of any custom attribute filter
foreach (System.Reflection.MethodInfo methodInfo in matchedMethods)
{
if (methodInfo.CustomAttributes.Count() == 0) { continue; }
// An alternative below is to explicitly check against a defined attribute type (e.g. `ca.AttributeType == ...`).
if (methodInfo.CustomAttributes.FirstOrDefault(ca => ca.ToString().IndexOf(attributeTypeString) == 0) !=null)
{
method = methodInfo;
break; // Break out of the 'foreach' loop since a match was found
}
}
}
else
{
method = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
Code notes
I used strongly-typed variable declarations (versus 'var') so it's easier to follow what the code is doing.
Add using System.Reflection; and using System.Linq at the top of the class file. I listed the full assembly declaration of a variable/type/flag in the code above so that again it's easier to follow (at least for me) in this answer.
The first line of code in the above solution can be broken into separate lines to make it easier to follow:
System.Reflection.MethodInfo[] allMethods = controllerType.GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
System.Reflection.MethodInfo[] matchedMethods = allMethods.Where(m => m.Name == actionName).ToArray<System.Reflection.MethodInfo>();
Note the if condition within the foreach loop.
if (methodInfo.CustomAttributes.FirstOrDefault(ca => ca.ToString().IndexOf(attributeTypeString) == 0) !=null)
The if condition doesn't have to convert the custom attribute to a string. An alternative is to explicitly check against a defined attribute type (e.g. ca.AttributeType == ...). If the condition does check against the text of an attribute name then ensure the string comparison method (e.g. IndexOf() used here) satisfies the conditions of your application. For example, I used IndexOf() > -1 to determine if the text of variable attributeTypeString is listed anywhere in a custom attribute because I assumed that there should not be another custom attribute that contains the text 'HttpGet'.
Supposed that I have two arrays:
Dim RoomName() As String = {(RoomA), (RoomB), (RoomC), (RoomD), (RoomE)}
Dim RoomType() As Integer = {1, 2, 2, 2, 1}
I want to get a value from the "RoomName" array based on a criteria of "RoomType" array. For example, I want to get a "RoomName" with "RoomType = 2", so the algorithm should randomize the index of the array that the "RoomType" is "2", and get a single value range from index "1-3" only.
Is there any possible ways to solve the problem using array, or is there any better ways to do this? Thank you very much for your time :)
Note: Code examples below using C# but hopefully you can read the intent for vb.net
Well, a simpler way would be to have a structure/class that contained both name and type properties e.g.:
public class Room
{
public string Name { get; set; }
public int Type { get; set; }
public Room(string name, int type)
{
Name = name;
Type = type;
}
}
Then given a set of rooms you can find those of a given type using a simple linq expression:
var match = rooms.Where(r => r.Type == 2).Select(r => r.Name).ToList();
Then you can find a random entry from within the set of matching room names (see below)
However assuming you want to stick with the parallel arrays, one way is to find the matching index values from the type array, then find the matching names and then find one of the matching values using a random function.
var matchingTypeIndexes = new List<int>();
int matchingTypeIndex = -1;
do
{
matchingTypeIndex = Array.IndexOf(roomType, 2, matchingTypeIndex + 1);
if (matchingTypeIndex > -1)
{
matchingTypeIndexes.Add(matchingTypeIndex);
}
} while (matchingTypeIndex > -1);
List<string> matchingRoomNames = matchingTypeIndexes.Select(typeIndex => roomName[typeIndex]).ToList();
Then to find a random entry of those that match (from one of the lists generated above):
var posn = new Random().Next(matchingRoomNames.Count);
Console.WriteLine(matchingRoomNames[posn]);
In Dashcode, if I have a dataSource that has, for example, 2 fields called 'FirstName' and 'Last Name', how do I concatenate the 2 fields into one text field in a list view?
I'm fairly sure it must be to use a value transformer, so say that I assign the 'FirstName' field to the textfield, and add a value transformer... how do I then add the 'LastName' value to the 'value' variable in the transformer.
I'm sure it's to do with dashcode.getDataSource and valueForKeyPath and I think I'm close to the solution but it all seems a bit ungainly so any help would be much appreciated.
Correct - you need to use a Value Transformer.
In the Transformer, you would code as follows:
itemDescription = Class.create(DC.ValueTransformer,{
transformedValue: function(value){
var itemDataSource = dashcode.getDataSource('itemsList'); // The Data Source Name here
var lastName = itemDataSource.selection().valueForKey('lastName'); // Presumes you have a field called lastName
return value + " " + lastName;
}
});
Hope this helps - I battled with this for a day!!!
For future googlers, since there is absolutely no documentation anywhere about this :
When in detailed view to concatenate two fields from same the datasource :
XML
<?xml version="1.0" encoding="utf-8"?>
<immobilier>
<bien>
<ID>1453</ID>
<Titre>Maison / Villa F4</Titre>
<Ville>Sainte Clotilde</Ville>
<Quartier>BRETAGNE</Quartier>
</bien>
</immobilier>
To combine the fields Ville and Quartier create a value transformer like so :
mapAdresse = Class.create(DC.ValueTransformer,{
transformedValue: function(value){
if (value.trim() != "") {
//Replace immoListe with your source name
var itemDataSource = dashcode.getDataSource('immoListe');
//THIS IS THE MOST IMPORTANT : HOW TO FIND THE CURRENTLY SELECTED ITEM INDEX
var selectedIndex = document.getElementById('list').selectedIndex;
//Use the selectedIndex to find the record in the datasource
var quartier = itemDataSource.selection().valueForKey("bien")[selectedIndex].valueForKey("Quartier");
//Concatenate to your liking
if (quartier.trim() != "") value = value + ", "+ quartier;
}
return value;
}
});
Why is this not documented anywhere ?? Beats me !!