Hello,
Please excuse if I'm missing some basic concepts here. I'm attempting to something along the lines of this code snippet, which I found on another forum post:
HierarchyDescriptor<ProductData> dateTimeTodayDescriptor = new HierarchyDescriptor<ProductData>(pd => pd.Today);
dateTimeTodayDescriptor.AddLevel(pd => "Today", "All Dates");
dateTimeTodayDescriptor.AddLevel(pd => pd.Today.SemesterWithYear(), "Semesters");
dateTimeTodayDescriptor.AddLevel(pd => pd.Today.MonthShort(), "Months");
However, instead of a known class (in the example, "ProductData"), the ItemSource for my XamPivotGrid consists of a list of dynamic objects created using Infragistics.Olap.DynamicTypeBuilder. I have the property names of the object available in string variables. Any suggestions on how I might modify this example to handle my situation?
I've also tried a completely different approach such as:
// Create a HierarchyDescriptor for a property whose name is stored in col.ColumnName (I'd like it displayed using the string in col.Caption)...
var hier = new HierarchyDescriptor { SourcePropertyName = col.ColumnName, HierarchyName = col.Caption, HierarchyDisplayName = col.Caption, };// Then add a hierarchy level for the property...
HierarchyLevelDescriptor yLevel = new HierarchyLevelDescriptor
{
LevelName = "Years",
LevelExpressionPath = col.ColumnName
};
System.Linq.Expressions.Expression<Func<DateTime, int>> eY = date => date.Year;
yLevel.LevelExpression = eY;
hier.LevelDescriptors.Add(yLevel);
But this doesn't work at all (note that the "System.Linq.Expressions....." line is a total guess, since the LevelExpression property has no useful documentation whatsoever -- please take note that "gets or sets the LevelExpressions property" as the entire explanation doesn't tell us much).
Hopefully I've communicated what I'm trying to do here. Any suggestions of a way to get it done would be greatly appreciated!
And as a side note, what does the HierarchyDisplayName property actually do? It seems to have no effect -- the top of each Hierarchy shows in the XamPivotDataSelector as the ugly raw property name, not the nicer looking "caption" I'm trying to set it to. Can't find a way around that one either...
Thanks,
Bob
Well, I have found one way that starts to work:
HierarchyLevelDescriptor yLevel = new HierarchyLevelDescriptor { LevelName = "Years", LevelExpressionPath = col.ColumnName + ".Year" }; hier.LevelDescriptors.Add(yLevel);But when I try to build the next level using a similar technique it fails (I can't drill in from Years to Quarters):
HierarchyLevelDescriptor qLevel = new HierarchyLevelDescriptor { LevelName = "Quarters", LevelExpressionPath = col.ColumnName + ".QuarterShort()" }; hier.LevelDescriptors.Add(qLevel);
I can't say I love having to build the LevelExpressionPath this way, writing code in a string literal, andit doesn't seem to work completely anyway (Why?). I'd think that using LevelExpression would be better, but again there's no documentation on how to use it.Help! :-)
This behavior is caused because LevelExpressionPath currently does not support method calls. I'm not sure if it will work but you can try to expose a property of some complex type with single property which returns the method call value:
public class QuarterShort
private DateTime _dateValue;
public QuarterShort(DateTime dateValue)
this._dateValue = dateValue;
}
public string Value
get { return this._dateValue.QuarterShort(); }
Now with dynamic type builder define property of type QuarterShort and name col.ColumnName + "QuarterShort" and then your expression should be: col.ColumnName + "QuarterShort.Value"
Best regards,Plamen
Thanks, Plamen, I'll have a look.
But is there no way to do it with LevelExpression? Can you please give an example of how one would use that property (to do anything)?
The fact that you can do something like dateTimeDescriptor.AddLevel<DateTime>(date => date.QuarterShort(), "Quarters"); when using "AppliesToPropertiesOfType" (which apparently doesn't allow you to customize things for specific properties, only set behavior for all properties of a given type) implies to me that there must be a way to do something similar on a particular property...
I feel like I'm missing something...
LevelExpression and LevelExpressionPath are properties that could be added to set the path which is used for resolving data from particular instance. The LevelExpression allows you to set the path as lambda expression. If you are using the LevelExpressionPath, there is no need to set the LevelExpression, too. Plamen suggested a custom approach that could help you achieve the functionality you need as these properties do not support method calls (“.QuarterShort()” in the provided code snippet). Using a property that provides the value returned by QuarterShort will allow you to set the LevelExpressionPath to the HierarchyLevelDescriptor.
Please feel free to let us know fi you have any other questions on this.
OK... Perhaps you can clear up a few things that are confusing to my decidedly non-expert mind...
1) Pardon my ignorance here, but isn't a Lambda expression essentially a way for me to pass you "code" to execute, without you really knowing what it is or does, as long as it takes the correct parameters and returns something reasonable? If so, then why do you care whether the code I pass references a property or method? Clearly you said that you do care, but I'd really like to understand why, because it makes no sense to me...
2) Is this behavior intentional (i.e. "feature" or "Bug" :-) )?
3) If the AddLevel<DateTime> method, which takes a Lambda expression, supports method calls, why doesn't setting the expression directly on a HierarchyLevelDescritpor support it? That also makes no sense to me as an outsider looking in...
4) Can you please consider this a feature request?
Hello Bob,
I understand your concerns. Since currently method calls are not supported, the best approach I could suggest you is getting the returned value of the method using a property. You could also go to this site http://ideas.infragistics.com where new Product Ideas are suggested and create one for this.
Steps to create your idea:
The benefits of submitting the product idea yourself include:
- Direct communication with our product management team regarding your product idea.
- Notifications whenever new information regarding your idea becomes available.
Additional benefits of the Product Idea system include:
- Ability to vote on your favorite product ideas to let us know which ones are the most important to you. You will have ten votes for this and can change which ideas you are voting for at any time.
- Allow you to shape the future of our products by requesting new controls and products altogether.
- You and other developers can discuss existing product ideas with members of our Product Management team.
The product ideas site allows you to track the progress of your ideas at any time, see how many votes it got, read comments from other developers in the community, and see if someone from the product team has additional questions for you.
OK I figured out what I think is a reasonable way to do this. I'd like to share it to hopefully spare others the same pain. Hope it helps!
The key is using DimensionMetadata objects (to which the key is the CubeMatada.DataTypeFullName property -- it MUST be set to the same value as DynamicTypeBuilder.DynamicTypeName (i.e. the type name of the objects in the ItemsSource); see http://ko.infragistics.com/community/forums/p/83388/416871.aspx#416871) and adding the HierarchyDescriptors to them. When doing it this way you can use the AddLevel<DateTime> method to add levels to the hierarchies and still use method calls in the Lambda expressions. This way also lets you customize the display of each property. Just what I was looking for!
Note: in the example below, "dt" is the original DataTable that the list of dynamic objects was built from.
flatDataSource.DimensionsGenerationMode = DimensionsGenerationMode.Mixed; CubeMetadata cubeMetadata = new CubeMetadata(); cubeMetadata.DisplayName = dt.TableName; cubeMetadata.DataTypeFullName = dt.TableName; // Same as DynamicTypeName foreach (DataColumn col in dt.Columns) { DimensionMetadata dm = new DimensionMetadata() { SourcePropertyName = col.ColumnName, DisplayName = col.Caption, }; if (col.DataType == typeof(DateTime)) { HierarchyDescriptor dateTimeDescriptor = new HierarchyDescriptor { AppliesToPropertiesOfType = typeof(DateTime) }; string allString = "All " + col.Caption + "s"; dateTimeDescriptor.AddLevel<DateTime>(date => allString, allString); dateTimeDescriptor.AddLevel<DateTime>(date => date.Year, "Years"); dateTimeDescriptor.AddLevel<DateTime>(date => date.QuarterShort(), "Quarters"); dateTimeDescriptor.AddLevel<DateTime>(date => date.MonthShort(), "Months"); dateTimeDescriptor.AddLevel<DateTime>(date => date.Date.ZenithDateString(), "Dates"); dm.HierarchyDescriptors.Add(dateTimeDescriptor); } else { HierarchyDescriptor hier = new HierarchyDescriptor { SourcePropertyName = col.ColumnName, HierarchyName = col.Caption, HierarchyDisplayName = col.Caption }; HierarchyLevelDescriptor allLevel = new HierarchyLevelDescriptor { LevelName = "All " + col.Caption + "s" }; hier.LevelDescriptors.Add(allLevel); HierarchyLevelDescriptor entriesLevel = new HierarchyLevelDescriptor { LevelName = col.Caption, LevelExpressionPath = col.ColumnName }; if (col.DataType == typeof(decimal)) entriesLevel.DisplayFormat = "C2"; hier.LevelDescriptors.Add(entriesLevel); dm.HierarchyDescriptors.Add(hier); } cubeMetadata.DimensionSettings.Add(dm); }