In the code below my itemssource does not change but one of the properties of the control changes, which changes which field is bound. I need to clear the datagrid items and force it to rebind. How do I do that? By the way, onpropertychanged for the Items property is raised but the grid does not rebuild.
Thank you,
Sam
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Windows;
System.Windows.Controls;
System.Windows.Data;
System.Windows.Documents;
System.Windows.Input;
System.Windows.Media;
System.Windows.Media.Imaging;
System.Windows.Navigation;
System.Windows.Shapes;
System.Collections.ObjectModel;
Poolman.Entities;
Poolman.Common;
Poolman.Models;
System.Threading;
System.Threading.Tasks;
Infragistics.Windows.DataPresenter;
Infragistics.Windows.DataPresenter.Events;
Infragistics.Controls.Editors;
Infragistics.Windows.DockManager;
namespace
Poolman.Controls
{
public partial class ExposureMatrixAccountGrid : Common.
BaseUserControl
public IList<ExposureItem
> Items
get { return (IList<ExposureItem
>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value
); }
}
public static readonly DependencyProperty
ItemsProperty =
DependencyProperty.Register("Items", typeof(IList<ExposureItem>), typeof(ExposureMatrixAccountGrid), new UIPropertyMetadata(null
,DataChanged));
public bool
IsQuantityView
get { return (bool
)GetValue(IsQuantityViewProperty); }
set { SetValue(IsQuantityViewProperty, value
IsQuantityViewProperty =
DependencyProperty.Register("IsQuantityView", typeof(bool), typeof(ExposureMatrixAccountGrid), new UIPropertyMetadata(new Boolean
(),ViewChanged));
private ObservableCollection<ExposureItem
> _GroupedItems;
public ObservableCollection<ExposureItem
> GroupedItems
get { return
_GroupedItems; }
set
if (_GroupedItems != value
)
_GroupedItems =
value
;
OnPropertyChanged(
"GroupedItems"
);
private bool
_LoadingData;
LoadingData
_LoadingData; }
if (_LoadingData != value
_LoadingData =
"LoadingData"
public decimal MinValue { get; set
; }
public decimal MaxValue { get; set
public XamDataGrid AccountGrid { get { return
Grid1; } }
IsDirty;
public
ExposureMatrixAccountGrid()
InitializeComponent();
SummaryCalculator.Register(MarketValueSummaryCalculator
.Calculator);
IsDirty =
true
IsVisibleChanged +=
new DependencyPropertyChangedEventHandler
(ExposureMatrixAccountGrid_IsVisibleChanged);
void ExposureMatrixAccountGrid_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs
e)
RebuildGrid();
public static void ViewChanged(DependencyObject sender, DependencyPropertyChangedEventArgs
ExposureMatrixAccountGrid control = sender as ExposureMatrixAccountGrid
control.IsDirty =
control.RebuildGrid();
public static void DataChanged(DependencyObject sender, DependencyPropertyChangedEventArgs
private void
RebuildGrid()
if (!IsDirty || this.Visibility != Visibility
.Visible)
return
LoadingData =
Grid1.DataSource =
null
new ObservableCollection<ExposureItem
>();
Grid1.DataSource = GroupedItems;
Task
.Factory.StartNew(() =>
// Group items by (not) Coupon
try
Dispatcher.BeginInvoke((
Action)delegate
()
MinValue = Items.Any() ? Items.Min(x => x.Qty) : 0;
MaxValue = Items.Any() ? Items.Max(x => x.Qty) : 0;
GroupedItems =
>(
Items
.GroupBy(x =>
new
{ x.AcctNo, x.Collateral, x.DeliveryDate, x.AcctMarketValue, x.PM_Name, x.Type })
.Select(x =>
ExposureItem
AcctNo = x.Key.AcctNo,
Collateral = x.Key.Collateral,
DeliveryDate = x.Key.DeliveryDate,
AcctMarketValue = x.Key.AcctMarketValue,
PM_Name = x.Key.PM_Name,
Type = x.Key.Type
})
.OrderBy(x => x.AcctNo));
false
});
finally
}).ContinueWith(x =>
if (x.Exception != null
throw new Exception("See Inner Exception"
, x.Exception);
},
TaskScheduler
.FromCurrentSynchronizationContext());
///
<summary>
Build out coupon coulums in datagrid. Add a column for total and for every distinct coupon.
</summary>
<param name="sender"></param>
<param name="e"></param>
private void Grid1_FieldLayoutInitialized(object sender, Infragistics.Windows.DataPresenter.Events.FieldLayoutInitializedEventArgs
Style AmountStyle = (Style)TryFindResource(IsQuantityView ? "AmountStyle" : "Percent3Style"
string stringFormat = "{0:" + ((Setter)AmountStyle.Setters[0]).Value.ToString() + "}"
SummaryCalculator
calculator;
List<decimal
> coupons = Items.Select(x => x.Coupon).OrderBy(x => x).Distinct().ToList();
coupons.Insert(0, -1m);
// Create a total column. Use minus one as a coupon to identify the total column
foreach (decimal coupon in
coupons)
string columnName = Guid.NewGuid().ToString();
// Generate a bogus field name so the summary calculator knows what to total
if
(IsQuantityView)
calculator =
new SumSummaryCalculator
();
else
new PctMarketValueSummaryCalculator
UnboundField unboundField = new
UnboundField
Name = columnName,
Label = coupon == -1 ?
"Total" : coupon.ToString("#.###") + "%"
,
DataType =
typeof(decimal
),
Settings =
new FieldSettings
{ EditorStyle = AmountStyle },
Width =
new FieldLength
(80),
};
MultiBinding mb = new MultiBinding { Converter = new CouponColumnConverter
() };
mb.Bindings.Add(
new Binding());
// The row being bound
new Binding { Source = coupon });
// The coupon that identifies the column.
new Binding { Source = Items });
// Lookup list to see if an entry for coupon for passed row exists
new Binding { Source = IsQuantityView });
// true to display qty, false to display pct mkt value.
new Binding
{ Source = unboundField });
{ Source = MinValue });
{ Source = MaxValue });
unboundField.Binding = mb;
e.FieldLayout.Fields.Add(unboundField);
Grid1.FieldLayouts[0].SummaryDefinitions.Add(
new SummaryDefinition
{ Calculator = calculator, StringFormat = stringFormat, SourceFieldName = columnName });
private void Grid1_InitializeRecord(object sender, InitializeRecordEventArgs
//e.Record.DataPresenter.Background = Brushes.Yellow;
//var zz = e.Record.FieldLayout.Fields[0].GetValue(CellValuePresenter.
private void Grid1_Loaded(object sender, RoutedEventArgs
//int rowCount = Grid1.Records.Count;
//if (rowCount == 0)
// return;
//int cellCount = ((DataRecord)Grid1.Records[0]).Cells.Count;
//for (int row = 0; row < rowCount; row++)
// for (int cell = 6; cell < cellCount; cell++)
// CellValuePresenter.FromCell((Grid1.Records[row] as DataRecord).Cells[cell]).Background = Brushes.Yellow;
public class CouponColumnConverter :
IMultiValueConverter
public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo
culture)
ExposureItem boundItem = (ExposureItem
)value[0];
decimal coupon = System.Convert.ToDecimal(value[1]);
// coupon will be minus one if this is the totals column
IList<ExposureItem> list = (IList<ExposureItem
>)value[2];
bool isQuantityView = (bool
)value[3];
UnboundField field = (UnboundField
)value[4];
decimal minValue = (decimal
)value[5];
decimal maxValue = (decimal
)value[6];
decimal
result = 0;
IEnumerable<ExposureItem
> items = list.Where(x =>
x.AcctNo == boundItem.AcctNo
&& x.Collateral == boundItem.Collateral
&& x.DeliveryDate == boundItem.DeliveryDate
&& x.PM_Name == boundItem.PM_Name
&& x.Type == boundItem.Type
&& (x.Coupon == coupon || coupon == -1));
// Sum all coupons if this is the totals column
if (items == null
return Binding
.DoNothing;
(isQuantityView)
result = items.Sum(x => x.Qty);
(items.Any() && items.First().AcctMarketValue != 0)
result = items.Sum(x => x.MktValue) / items.First().AcctMarketValue;
//MultiBinding heatMap = new MultiBinding { Converter = new Converters.HeatMapConverter() };
//heatMap.Bindings.Add(new Binding { Source = result });
//heatMap.Bindings.Add(new Binding { Source = minValue });
//heatMap.Bindings.Add(new Binding { Source = maxValue });
//Style backgroundStyle = new Style();
//backgroundStyle.Setters.Add(new Setter { Property = System.Windows.Controls.Control.BackgroundProperty, Value = heatMap });
//field.Settings.CellValuePresenterStyle = backgroundStyle;
result;
public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo
throw new NotImplementedException
Accounts may be repeated on multiple rows becuse each security type is on its own row.
This class ensures the account market value for each account is counted once only.
public class MarketValueSummaryCalculator :
SumSummaryCalculator
static MarketValueSummaryCalculator
_Calculator;
public static MarketValueSummaryCalculator
Calculator
get
if (_Calculator == null
_Calculator =
new MarketValueSummaryCalculator
private List<decimal
> SummedAccounts;
MarketValueSummaryCalculator()
SummedAccounts =
new List<decimal
public override void BeginCalculation(SummaryResult
summaryResult)
SummedAccounts.Clear();
base
.BeginCalculation(summaryResult);
public override void Aggregate(object dataValue, SummaryResult summaryResult, Record
record)
ExposureItem item = (ExposureItem)((DataRecord
)record).DataItem;
(SummedAccounts.Where(x => x == item.AcctNo).Any())
SummedAccounts.Add(item.AcctNo);
.Aggregate(dataValue, summaryResult, record);
public override string
Name
get { return "MarketValueSummaryCalculator"
Summs MarketValue / AccountMarketValue
public class PctMarketValueSummaryCalculator :
static PctMarketValueSummaryCalculator
public static PctMarketValueSummaryCalculator
private decimal
MktValue;
AcctMktValue;
PctMarketValueSummaryCalculator()
MktValue += (
Convert
.ToDecimal(dataValue) * item.AcctMarketValue);
(!SummedAccounts.Where(x => x == item.AcctNo).Any())
AcctMktValue += item.AcctMarketValue;
public override object EndCalculation(SummaryResult
AcctMktValue == 0 ? 0 : MktValue / AcctMktValue;
get { return "PctMarketValueSummaryCalculator"
<
common:BaseUserControl x:Class
="Poolman.Controls.ExposureMatrixAccountGrid"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:igDP
="http://infragistics.com/DataPresenter"
xmlns:xamSpin
="clr-namespace:xamlSpinnersWPF;assembly=BlackSpike.XamSpinner"
xmlns:common="clr-namespace:Poolman.Common"
xmlns:views
="clr-namespace:Poolman.Views"
xmlns:controls
="clr-namespace:Poolman.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth
="300">
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type common:BaseUserControl
}}}" >
<igDP:XamDataGrid x:Name
="Grid1"
Grid.Row
="0"
FieldLayoutInitialized
="Grid1_FieldLayoutInitialized"
InitializeRecord
="Grid1_InitializeRecord"
Loaded
="Grid1_Loaded"
ScrollViewer.HorizontalScrollBarVisibility
="Auto"
DataSource="{Binding GroupedItems
}"
GroupByAreaLocation
="None">
<igDP:XamDataGrid.FieldSettings
>
<igDP:FieldSettings AllowEdit="False"
SummaryDisplayArea
="BottomFixed"
AllowRecordFiltering
="True"
FilterLabelIconDropDownType
="MultiSelectExcelStyle"
CellClickAction
="SelectRecord"/>
</igDP:XamDataGrid.FieldSettings
<igDP:XamDataGrid.FieldLayoutSettings
<igDP:FieldLayoutSettings
AllowDelete
="False"
AllowAddNew
AllowFieldMoving
="WithinLogicalRow"
AutoGenerateFields
HighlightAlternateRecords
RecordSelectorLocation
="None"
FilterUIType
="LabelIcons"/>
</igDP:XamDataGrid.FieldLayoutSettings
<igDP:XamDataGrid.FieldLayouts
<igDP:FieldLayout
<igDP:FieldLayout.SortedFields
<igDP:FieldSortDescription
Direction="Ascending"
FieldName
="ACCT_NO"/>
</igDP:FieldLayout.SortedFields
<igDP:FieldLayout.Fields
<igDP:Field Name="AcctNo" Label="Acct" FixedLocation="FixedToNearEdge" Width
="60">
<igDP:Field.Settings
<igDP:FieldSettings EditorStyle="{StaticResource PoolmanDecimalStyle
}"/>
</igDP:Field.Settings
</igDP:Field
<igDP:Field Name="PM_Name" Label="PM" FixedLocation
="FixedToNearEdge" />
<igDP:Field Name="Collateral" Label="Coll." Width="60" FixedLocation
="FixedToNearEdge"/>
<igDP:Field Name="Type" Label="Type" Width="60" FixedLocation
<igDP:Field Name="AcctMarketValue" Label
="MV">
<igDP:FieldSettings EditorStyle="{StaticResource AmountStyle
<igDP:Field Name="DeliveryDate" Label
="Dlvry Date">
</igDP:FieldLayout.Fields
<igDP:FieldLayout.SummaryDefinitions
<igDP:SummaryDefinition SourceFieldName="AcctMarketValue"
Calculator="{x:Static controls:MarketValueSummaryCalculator
.Calculator}"
StringFormat
="{}{0:#,#;(#,#)}" />
<igDP:SummaryDefinition SourceFieldName="PctMktValue"
="Avg"
="{}{0:#,#;(#,#)}"/>
</igDP:FieldLayout.SummaryDefinitions
</igDP:FieldLayout
</igDP:XamDataGrid.FieldLayouts
</igDP:XamDataGrid
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="216" Width="216" Grid.Row
Visibility="{Binding Path=LoadingData, Converter={StaticResource BoolToVisConverter
}}">
<xamSpin:ucSpinnerApple
<xamSpin:ucSpinnerApple.RenderTransform
<ScaleTransform ScaleX="9" ScaleY
="9"/>
</xamSpin:ucSpinnerApple.RenderTransform
</xamSpin:ucSpinnerApple
</Canvas
</Grid
</
common:BaseUserControl
Hi Stephan, when the list that is used as the datasource for this grid changes, the grid does not rebuild. So my question is how do I make the grid rebuild.
Thanks,
Hello Sam,
Since the List doesn't implement the INotifyCollectionChanged interface, it is expected that the XamDataGrid doesn't update its Records. My suggestion is to use an ObservableCollection, which implement this interface.