Workaround: remove the localization provider before saving the layout and then add it back.
Need to have the ability to resize the height of the aggregate area along with other features that will help the user see/discern the labels properly
Request is to have the ability preferably using a mouse drag to change the height of the column headers in the grid. We can already do that for data rows of the grid, but it is not possible currently to do the same for the header row.
RadPivotGrid Implement logic when the user clicks on a cell to get the underlying data
Until the feature gets implemented create a custom PivotFieldListVisualItem and translate each of the items individually: public partial class Form1 : Form { public Form1() { InitializeComponent(); this.radPivotFieldList1.RowLabelsControl.CreatingVisualListItem += ListControl_CreatingVisualListItem; this.radPivotFieldList1.ColumnLabelsControl.CreatingVisualListItem += ListControl_CreatingVisualListItem; this.radPivotFieldList1.ReportFiltersControl.CreatingVisualListItem += ListControl_CreatingVisualListItem; this.radPivotFieldList1.ValuesControl.CreatingVisualListItem += ListControl_CreatingVisualListItem; } private void ListControl_CreatingVisualListItem(object sender, CreatingVisualListItemEventArgs args) { args.VisualItem = new MyPivotFieldListVisualItem(this.radPivotFieldList1.ViewModel); } } public class MyPivotFieldListVisualItem : PivotFieldListVisualItem { public MyPivotFieldListVisualItem(FieldListViewModel viewModel) : base(viewModel) { } protected override void CreateChildElements() { base.CreateChildElements(); CommandBarDropDownButton btn = this.GetType().BaseType .GetField("button", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as CommandBarDropDownButton; if (btn != null) { btn.DropDownMenu.PopupOpening += DropDownMenu_PopupOpening; } } private void DropDownMenu_PopupOpening(object sender, System.ComponentModel.CancelEventArgs args) { foreach (RadItem item in ((RadDropDownMenu)sender).Items) { // Validate and localize each of the items if (item is RadMenuItem) { item.Text = "MyText"; } } } }
Until the feature becomes available use the following workaround: MyPivotGridChartDataProvider chartProvider = new MyPivotGridChartDataProvider(this.radPivotGrid1.PivotGridElement); this.radPivotGrid1.ChartDataProvider = chartProvider; this.radChartView1.DataSource = this.radPivotGrid1; this.radChartView1.ShowLegend = true; this.radPivotGrid1.ChartDataProvider.SeriesAxis = Telerik.Pivot.Core.PivotAxis.Rows; this.radPivotGrid1.ChartDataProvider.GeneratedSeriesType = Telerik.WinControls.UI.GeneratedSeriesType.Line; public class MyPivotGridChartDataProvider : PivotGridChartDataProvider { public MyPivotGridChartDataProvider(RadPivotGridElement pivotGridElement) : base(pivotGridElement) { } public override void UpdateChartData() { base.UpdateChartData(); foreach (ChartSeries series in this.ChartView.Series) { CartesianSeries cartesianSeries = series as CartesianSeries; if (cartesianSeries == null) { continue; } cartesianSeries.PointSize = new SizeF(7, 7); BindingList<PivotChartModelPoint> newData = new BindingList<PivotChartModelPoint>(); BindingList<PivotDataPoint> points = cartesianSeries.DataSource as BindingList<PivotDataPoint>; foreach (PivotDataPoint point in points) { PivotChartModelPoint current = new PivotChartModelPoint() { Group = point.PivotGroup }; if (point.Value != 0) { current.Value = point.Value; } else { current.Value = null; } newData.Add(current); } cartesianSeries.DataSource = null; cartesianSeries.CategoryMember = "Group"; cartesianSeries.ValueMember = "Value"; cartesianSeries.DataSource = newData; } } } public class PivotChartModelPoint { public string Group{ get; set; } public double? Value { get; set; } }
How to reproduce: check the attached video Workaround: private void button1_Click(object sender, EventArgs e) { this.radPivotFieldList1.DragDropService.PreviewDragDrop += DragDropService_PreviewDragDrop; } IGroupDescription cache; string group; private void DragDropService_PreviewDragDrop(object sender, Telerik.WinControls.RadDropEventArgs e) { TreeNodeElement nodeElement = e.DragInstance as TreeNodeElement; if (nodeElement != null) { IField field = nodeElement.Data.DataBoundItem as IField; string draggedItem = field.FieldInfo.Name; IGroupDescription rowDesc = this.radPivotGrid1.RowGroupDescriptions.Where(i => i.GetUniqueName() == draggedItem).FirstOrDefault(); if (rowDesc != null) { cache = (IGroupDescription)rowDesc.Clone(); group = "Row"; } IGroupDescription colDesc = this.radPivotGrid1.ColumnGroupDescriptions.Where(i => i.GetUniqueName() == draggedItem).FirstOrDefault(); if (colDesc != null) { cache = (IGroupDescription)colDesc.Clone(); group = "Column"; } if (cache != null) { this.radPivotGrid1.UpdateCompleted += radPivotGrid1_UpdateCompleted; } } } private void radPivotGrid1_UpdateCompleted(object sender, EventArgs e) { this.radPivotGrid1.UpdateCompleted -= radPivotGrid1_UpdateCompleted; switch (group) { case "Row": this.radPivotGrid1.RowGroupDescriptions.Add(cache); break; case "Column": this.radPivotGrid1.ColumnGroupDescriptions.Add(cache); break; default: break; } cache = null; }
How to reproduce: var data = this.dbContext.Orders.Where(o => o.OrderID > 10500).Select(o => new { Id = o.OrderID, OrderDate = o.OrderDate, ShipDate = o.ShippedDate, Freight = o.Freight }).ToArray(); this.localDataProvider = new LocalDataSourceProvider() {ItemsSource = data}; Workaround: 1. Instead of ToArray call ToList var data = this.dbContext.Orders.Where(o => o.OrderID > 10500).Select(o => new { Id = o.OrderID, OrderDate = o.OrderDate, ShipDate = o.ShippedDate, Freight = o.Freight }).ToList(); this.localDataProvider = new LocalDataSourceProvider() {ItemsSource = data}; 2. Call the ToArray method but do not create anonymous objects. var data = this.dbContext.Orders.Where(o => o.OrderID > 10500).Select(o => new PivotModel { Id = o.OrderID, OrderDate = o.OrderDate, ShipDate = o.ShippedDate, Freight = o.Freight }).ToArray(); this.localDataProvider = new LocalDataSourceProvider() {ItemsSource = data}; public class PivotModel { public int Id { get; set; } public DateTime? OrderDate { get; set; } public DateTime? ShipDate { get; set; } public decimal? Freight { get; set; } }
Workaround: private void PrintPivotGrid() { MyPivotGridPrintStyle style = new MyPivotGridPrintStyle(); style.LayoutType = PivotLayout.Tabular; this.radPivotGrid1.PrintStyle = style; this.radPivotGrid1.PrintPreview(); } public class MyPivotGridPrintStyle : PivotGridPrintStyle { public override void Initialize() { base.Initialize(); FieldInfo fiColumnWidths = this.GetType().BaseType.GetField("columnWidths", BindingFlags.Instance | BindingFlags.NonPublic); List<int> columnWidths = (List<int>)fiColumnWidths.GetValue(this); RadPivotGridElement pivotGrid = (RadPivotGridElement)this.GetType().BaseType.GetField("pivotGrid", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this); for (int i = 0; i < pivotGrid.RowDescriptorsArea.Children.Count; i++) { RadElement descriptor = pivotGrid.RowDescriptorsArea.Children[i]; columnWidths[i] = descriptor.Size.Width; } } }
Workaround: public Form1() { InitializeComponent(); this.radPivotFieldList1.ValuesControl.CreatingVisualListItem += Aggregates_CreatingVisualListItem; } private void Aggregates_CreatingVisualListItem(object sender, Telerik.WinControls.UI.CreatingVisualListItemEventArgs args) { args.VisualItem = new MyPivotFieldListVisualItem(this.radPivotFieldList1.ViewModel); } public class MyPivotFieldListVisualItem : PivotFieldListVisualItem { private FieldListViewModel viewModel; private CommandBarDropDownButton button; private RadMenuItem sumMenuItem; private RadMenuItem avgMenuItem; private RadMenuItem countMenuItem; public MyPivotFieldListVisualItem(FieldListViewModel viewModel) : base(viewModel) { this.viewModel = viewModel; } protected override void CreateChildElements() { base.CreateChildElements(); this.sumMenuItem = this.GetType().BaseType .GetField("sumMenuItem", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadMenuItem; this.avgMenuItem = this.GetType().BaseType .GetField("avgMenuItem", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadMenuItem; this.countMenuItem = this.GetType().BaseType .GetField("countMenuItem", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadMenuItem; if (sumMenuItem != null && avgMenuItem != null && countMenuItem != null) { sumMenuItem.Click += OnAggregateFunctionClick; avgMenuItem.Click += OnAggregateFunctionClick; countMenuItem.Click += OnAggregateFunctionClick; } this.button = this.GetType().BaseType .GetField("button", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as CommandBarDropDownButton; RadMenuItem aggregateOptionsMenuItem = this.GetType().BaseType .GetField("aggregateOptionsMenuItem", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadMenuItem; aggregateOptionsMenuItem.Click += aggregateOptionsMenuItem_Click; RadMenuItem numberFormatMenuItem = this.GetType().BaseType .GetField("numberFormatMenuItem", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadMenuItem; numberFormatMenuItem.Click += numberFormatMenuItem_Click; } private void numberFormatMenuItem_Click(object sender, EventArgs e) { Value value = (this.Data.DataBoundItem as Value); if (value == null) { return; } MyNumberFormatOptionsDialog dialog = new MyNumberFormatOptionsDialog(); dialog.ThemeName = this.GetThemeName(); QueryableAggregateDescription queryableAggregateDescription = (value.Description as QueryableAggregateDescription); if (queryableAggregateDescription != null) { dialog.LoadQueryableSettings(queryableAggregateDescription); } System.Windows.Forms.DialogResult result = dialog.ShowDialog(); if (result == System.Windows.Forms.DialogResult.OK) { queryableAggregateDescription.StringFormat = dialog.SelectedStringFormat; this.viewModel.ExecuteUpdate(); } } private void aggregateOptionsMenuItem_Click(object sender, EventArgs e) { MyAggregateOptionsDialog dialog = new MyAggregateOptionsDialog(); dialog.ThemeName = this.GetThemeName(); Value value = (this.Data.DataBoundItem as Value); if (value != null) { QueryablePropertyAggregateDescriptionBase queryableAggregateDescription = (value.Description as QueryablePropertyAggregateDescriptionBase); if (queryableAggregateDescription != null) { dialog.LoadQueryableSettings(queryableAggregateDescription); } System.Windows.Forms.DialogResult result = dialog.ShowDialog(); if (result == System.Windows.Forms.DialogResult.OK) { queryableAggregateDescription.AggregateFunction = dialog.SelectedQueryableAggregateFunction; queryableAggregateDescription.CustomName = dialog.CustomName; this.Synchronize(); this.viewModel.ExecuteUpdate(); } } } private void OnAggregateFunctionClick(object sender, EventArgs e) { Value value = (this.Data.DataBoundItem as Value); string function = ((RadMenuItem)sender).Text; if (value != null && this.SetNewAggregateFunction(value.Description, function)) { this.Synchronize(); this.viewModel.ExecuteUpdate(); } } private bool SetNewAggregateFunction(IAggregateDescription description, string function) { QueryablePropertyAggregateDescriptionBase queryableDescription = (description as QueryablePropertyAggregateDescriptionBase); if (queryableDescription != null) { switch (function) { case "Sum": queryableDescription.AggregateFunction = QueryableAggregateFunction.Sum; break; case "Count": queryableDescription.AggregateFunction = QueryableAggregateFunction.Count; break; case "Average": queryableDescription.AggregateFunction = QueryableAggregateFunction.Average; break; default: return false; } return true; } return false; } protected override void SynchronizeProperties() { base.SynchronizeProperties(); Value value = (this.Data.DataBoundItem as Value); Label label = (this.Data.DataBoundItem as Label); if (value != null) { #if !NETFX2 QueryablePropertyAggregateDescription queryableDescription = (value.Description as QueryablePropertyAggregateDescription); if (queryableDescription != null) { this.sumMenuItem.IsChecked = queryableDescription.AggregateFunction == QueryableAggregateFunction.Sum; this.countMenuItem.IsChecked = queryableDescription.AggregateFunction == QueryableAggregateFunction.Count; this.avgMenuItem.IsChecked = queryableDescription.AggregateFunction == QueryableAggregateFunction.Average; } #endif } } private string GetThemeName() { if (this.ElementTree == null) { return string.Empty; } RadControl control = this.ElementTree.Control as RadControl; return control != null ? control.ThemeName : string.Empty; } } public class MyAggregateOptionsDialog : AggregateOptionsDialog { private RadListControl listAggregateFunctions; private RadLabel labelFieldName; private RadTextBox textBoxCustomName; public MyAggregateOptionsDialog() { this.listAggregateFunctions = this.GetType().BaseType .GetField("listAggregateFunctions", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadListControl; this.labelFieldName = this.GetType().BaseType .GetField("labelFieldName", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadLabel; this.textBoxCustomName = this.GetType().BaseType .GetField("textBoxCustomName", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadTextBox; } private readonly IList<QueryableAggregateFunction> availableQueryableAggregateFunctions = new List<QueryableAggregateFunction>() { QueryableAggregateFunction.Sum, QueryableAggregateFunction.Count, QueryableAggregateFunction.Average, QueryableAggregateFunction.Max, QueryableAggregateFunction.Min }; public virtual QueryableAggregateFunction SelectedQueryableAggregateFunction { get { return (QueryableAggregateFunction)this.listAggregateFunctions.SelectedValue; } } public virtual void LoadQueryableSettings(QueryablePropertyAggregateDescriptionBase aggregateDescription) { if (this.listAggregateFunctions.DataSource != null) { this.listAggregateFunctions.DataSource = availableQueryableAggregateFunctions; } this.listAggregateFunctions.SelectedValue = aggregateDescription.AggregateFunction; this.labelFieldName.Text = aggregateDescription.PropertyName; this.Text = String.Format("{0}{1}{2}", "Aggregate Options (", aggregateDescription.PropertyName, ")"); this.textBoxCustomName.Text = aggregateDescription.CustomName; } } public class MyNumberFormatOptionsDialog : NumberFormatOptionsDialog { private TextBox textBox; public MyNumberFormatOptionsDialog() { RadDropDownList dropDownListFormat = this.GetType().BaseType .GetField("dropDownListFormat", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this) as RadDropDownList; this.textBox = (TextBox)dropDownListFormat.DropDownListElement.EditableElement.TextBox.TextBoxItem.HostedControl; } public virtual void LoadQueryableSettings(QueryableAggregateDescriptionBase aggregateDescription) { this.textBox.Text = aggregateDescription.StringFormat; this.Text = String.Format(PivotGridLocalizationProvider.CurrentProvider.GetLocalizedString(PivotStringId.NumberFormatOptionsDialogFormatOptionsDescription), aggregateDescription.DisplayName); this.textBox.Select(this.textBox.Text.Length, 0); this.textBox.Focus(); } }
Until the feature gets implemented use custom PivotGridPrintStyle: Public Class MyPivotGridPrintStyle Inherits PivotGridPrintStyle Const MIN_SPACE As Integer = 1 Public Overrides Sub DrawPage(drawArea As Rectangle, graphics As Graphics, pageNumber As Integer) If Me.PivotGrid.ColumnHeaderHeight > MIN_SPACE Then MyBase.DrawPage(drawArea, graphics, pageNumber) Else Dim x As Integer = drawArea.X Dim y As Integer = drawArea.Y Dim scale As SizeF = DirectCast(Me.GetType().BaseType.GetMethod("GetScaleFactors", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(Me, New Object() {drawArea}), SizeF) Dim startColumn As Integer = DirectCast(Me.GetType().BaseType.GetMethod("GetStartColumn", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(Me, New Object() {pageNumber, drawArea, scale.Width}), Integer) Dim endColumn As Integer = DirectCast(Me.GetType().BaseType.GetMethod("GetEndColumn", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(Me, New Object() {startColumn, drawArea, scale.Width}), Integer) Dim startRow As Integer = DirectCast(Me.GetType().BaseType.GetMethod("GetStartRow", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(Me, New Object() {pageNumber, drawArea, scale.Height}), Integer) Dim endRow As Integer = DirectCast(Me.GetType().BaseType.GetMethod("GetEndRow", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(Me, New Object() {startRow, drawArea, scale.Height}), Integer) If Me.PivotGrid.ColumnHeaderHeight <= MIN_SPACE Then startRow += 1 End If For i As Integer = startRow To endRow x = drawArea.X Dim maxHeight As Integer = 0 For j As Integer = startColumn To endColumn Dim columnWidths = DirectCast(Me.GetType().BaseType.GetField("columnWidths", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(Me), List(Of Integer)) Dim rowHeights = DirectCast(Me.GetType().BaseType.GetField("rowHeights", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(Me), List(Of Integer)) Dim elementRect As New Rectangle(x, y, columnWidths(j), rowHeights(i)) Dim printElement As RadPrintElement = Me.GetPrintElementForCell(i, j) printElement.ScaleTransform = scale Dim transformedRect As RectangleF = printElement.GetTransformedBounds(elementRect) Me.PrintElement(printElement, drawArea, elementRect, graphics) x += CInt(Math.Floor(transformedRect.Width)) maxHeight = Math.Max(maxHeight, CInt(Math.Floor(transformedRect.Height))) Next y += maxHeight Next End If End Sub End Class
You save 2 config, one with Report filter (1), one without (2), if you load first (1), if puts report filter correctly, but if you load then (2) - report filter still as on (1). Also, if you load config with ShowFilterArea=true - it stays visible if you load another config with ShowFilterArea=true Hello Alex, While investigating the reported behavior I managed to isolate an issue in the Save/Load API of RadPivotGrid regarding the ShowFilterArea property. The default value of this property is not serialized, however this can be altered by adding a serialization meta data to the XmlSerializationInfo instance of the pivot. In this scenario the engine did not respect the added new data. Here is the feedback item and you can subscribe to it: http://feedback.telerik.com/Project/154/Feedback/Details/196273-fix-radpivotgrid-the-saveloadlayout-string-overload-does-not-use-the-radpivotg. The item is already in development and a permanent fix will be available with our next release. Regarding the empty filter descriptions, in order to serialize them one should work with a DataProviderSerializer class. Currently our engine does not save the empty filters and we will consider modifying it so that even if the collection is empty it also be serialized. I am attaching to this post a sample project with which you would be able to achieve both of your tasks. Please note that the serialization API of the LocalDataSourceProvider uses the DataContract and you would need to use our .NET 4.0 assemblies. I hope this helps. In case you need additional assistance please write here or open a support ticket. Regards, Hristo
How to reproduce check the attached project and video Workaround: handle the UpdateCompleted event and explicitly set the properties to true public LocalDataSourceSerializerForm() { InitializeComponent(); this.radPivotGrid1.AutoExpandColumnHeaders = false; this.radPivotGrid1.AutoExpandRowHeaders = false; this.radPivotGrid1.UpdateCompleted += radPivotGrid1_UpdateCompleted; } private void radPivotGrid1_UpdateCompleted(object sender, EventArgs e) { this.radPivotGrid1.AutoExpandColumnHeaders = true; this.radPivotGrid1.AutoExpandRowHeaders = true; }
Currently the words: Row, Column and Value are not localizable in the ScreenTip. Currently they can be localized as follows: void radPivotGrid1_ScreenTipNeeded(object sender, Telerik.WinControls.ScreenTipNeededEventArgs e) { PivotCellElement cell = e.Item as PivotCellElement; if (cell == null || cell.ScreenTip == null) { return; } RadOffice2007ScreenTipElement screenTip = cell.ScreenTip asRadOffice2007ScreenTipElement; screenTip.MainTextLabel.Text = screenTip.MainTextLabel.Text .Replace("Value:", "ChangedValue:") .Replace("Row:", "ChangedRow:") .Replace("Column:", "ReplacedColumn:"); }
Workaround: public class MyRadPivotGrid : RadPivotGrid { public override void SaveLayout(string fileName) { ComponentXmlSerializer ser = new ComponentXmlSerializer(this.XmlSerializationInfo); using (XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.UTF8)) { writer.Formatting = Formatting.Indented; writer.WriteStartElement("RadPivotGrid"); ser.WriteObjectElement(writer, this); } } }
Workaround: create a custom Top10FilterOptionsDialog public Form1() { InitializeComponent(); this.radPivotFieldList1.DialogsFactory = new MyDialogsFactory(); } public class MyDialogsFactory : PivotGridDialogsFactory { public override ITop10FilterOptionsDialog CreateTop10FilterOptionsDialog() { return new MyTop10FilterOptionsDialog(); } } public class MyTop10FilterOptionsDialog : Top10FilterOptionsDialog { public override void LoadSettings(Telerik.Pivot.Core.Filtering.ITopGroupsFilter filter, string fieldName, IEnumerable<string> aggregateNames) { base.LoadSettings(filter, fieldName, aggregateNames); if (filter != null) { ((RadDropDownList)this.Controls["groupBox"].Controls["dropDownTopBottom"]).SelectedValue = filter.Selection; } } }