I have a problem with my RadGridView not updating when new items are added to the source collection.
The ItemSource for my RadGridView is bound to a QueryableCollectionView which is created using a Caliburn.Micro BindableCollection e.g. new QueryableCollectionView(myBindableCollection).
I have several filters that I add as FilterDescriptors and CompositeFilterDescriptors to the QueryableCollectionView. And the filters works as they should.
The problem comes when I want to add a new item. The item is added to the BindableCollection and should show up in the RadGridView. However, this does only work when there is no FilterDescriptors on the QueryableCollectionView.
What I have tried:
1. To NotifyOfPropertyChanged on the QueryableCollectionView
2. To NotifyOfPropertyChanged on the BindableCollection
3 To run QueryableCollectionView.Refresh()
But none of the above has worked.
What seems to work though is to remove all the FilterDescriptors and add them back again. Then the new item appears. But it doesn't seem like a good solution.
Is there anything else that I can try?
7 Answers, 1 is accepted
Hello Martin,
I've tested this on my side, but the RadGridView control is updated when a new item is added even when filtering is applied. Can you please test the attached project and let me know if I am missing anything?
Regards,
Martin Ivanov
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.
Hi Martin, thanks for your reply. It looks similar to the code that I have. But one difference that I notice is that I bind my QueryableCollectionView to a BindableCollection (which is a Caliburn.Micro object, but inherits ObservableCollection).
Is there any know issues with QueryableCollectionView and the Caliburn.Micro BindableCollection?
One more thing that I noticed when debugging was that the Count and InternalCount of my QueryableCollectionView does not updated when an item is added to the ObservableCollection (yes I tried changing to an ObservableCollection instead of a BindableCollection to see if there was any difference, but it wasn't). The only counting property that updates is TotalCount, which is updated correctly.
When debugging your test project those two properties does update. And the same goes for when I remove the FilterDescriptors in my project.
Hello Martin,
We are not aware of any issues with the QueryableCollectionView in combination with the Caliburn.Micro's BindableCollection. Also, there shouldn't be any difference whether the collection is defined in code-behind or in the view model.
Can you share code that shows how the RadGridView and the QuaryableCollectionView are defined and populate with data on your side?
Regards,
Martin Ivanov
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.
Here is how I create my RadGridView (it is very large, due to the amount of columns it contains):
<telerik:RadGridView
x:Name="IncidentList"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
d:DataContext="{d:DesignInstance Type=viewModels:IncidentItemViewModel,
IsDesignTimeCreatable=False,
CreateList=True}"
AutoGenerateColumns="False"
FrozenColumnsSplitterVisibility="Hidden"
GroupRenderMode="Flat"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=IncidentListCollectionView, Mode=OneWay}"
SelectionMode="Extended"
SelectionUnit="FullRow"
ShowGroupPanel="False"
ShowSearchPanel="True"
Style="{StaticResource TelerikDataGridAlternatingSelectableRows}"
Tag="{Binding}"
Template="{DynamicResource RadGridColumnManageTemplate}">
<i:Interaction.Behaviors>
<behaviors:RadGridViewSelectedItemsBehavior SelectedItems="{Binding SelectedIncidentItems}" />
</i:Interaction.Behaviors>
<telerik:RadGridView.ControlPanelItems>
<telerik:ControlPanelItem ButtonContent="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ButtonContent_ManageColumns}">
<telerik:ControlPanelItem.Content>
<!-- List of columns name available on IncidentList -->
<ListBox
x:Name="ColumnsName"
BorderThickness="0"
ItemsSource="{Binding Columns}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox
x:Name="ColumnCheckBox"
Content="{Binding Header, Mode=OneWay}"
IsChecked="{Binding IsVisible, Mode=TwoWay}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Header, Mode=OneWay}" Value="">
<Setter TargetName="ColumnCheckBox" Property="Content" Value="{Binding Name}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</telerik:ControlPanelItem.Content>
</telerik:ControlPanelItem>
</telerik:RadGridView.ControlPanelItems>
<telerik:RadGridView.Columns>
<!-- incident icon column -->
<telerik:GridViewDataColumn
x:Name="IncidentIcon"
Width="Auto"
CellStyle="{StaticResource IncidentIconCellStyle}"
DataMemberBinding="{Binding IncidentIcon, Mode=OneWay}"
DataType="{x:Null}"
FilterMemberPath="TranslatedPriority"
Header=""
IsReorderable="False"
IsResizable="False"
SortMemberPath="Priority" />
<!-- IncidentKey column -->
<telerik:GridViewDataColumn
DataMemberBinding="{Binding IncidentKey, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderIncidentId}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}"
ShowDistinctFilters="False">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Setter Property="ToolTip" Value="{Binding Id, Mode=OneWay}" />
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- IncidentCategory column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding IncidentCategory, Mode=OneWay, Converter={StaticResource IncidentCategoryToTextConverter}}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderIncidentCategory}"
IsReadOnly="True" />
<!-- ReasonCodeName column -->
<telerik:GridViewDataColumn
DataMemberBinding="{Binding ReasonCodeName, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderIncidentType}"
Style="{StaticResource LongTextColumnStyle}">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Setter Property="ToolTip" Value="{Binding ReasonCodeName, Mode=OneWay}" />
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- Location column -->
<telerik:GridViewDataColumn
Width="120"
MaxWidth="476"
DataMemberBinding="{Binding LocationText, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderLocation}"
Style="{StaticResource LongTextColumnStyle}">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Setter Property="ToolTip" Value="{Binding LocationText, Mode=OneWay}" />
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- AssignedTo column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding PreviouslyAssignedTo, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderAssignedTo}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- SourceReference column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding SourceReference, Mode=OneWay, Converter={StaticResource IncidentSourceToLanguageConverter}}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderSourceReference}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- CreatedBy column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding CreatedBy}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_Created}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- Actionplan namn column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_Actionplan}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- Description column -->
<telerik:GridViewDataColumn
Width="180"
DataMemberBinding="{Binding Description, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderDescription}"
Style="{StaticResource LongTextColumnStyle}">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Setter Property="ToolTip" Value="{Binding Description, Mode=OneWay}" />
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- StartedAtLocal column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding StartedAtLocal, Mode=OneWay, StringFormat='{}{0:dd.MM.yyyy HH:mm}'}"
FilterMemberPath="StartedAtLocal.Date"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderStartTime}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- EstimatedEndLocal column -->
<telerik:GridViewDataColumn
DataMemberBinding="{Binding EstimatedEndLocal, Mode=OneWay, StringFormat='{}{0:dd.MM.yyyy HH:mm}'}"
FilterMemberPath="TranslatedEstimatedEndLocalDate.Date"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderEstimatedEndTime}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding>
<MultiBinding.Converter>
<valueConverters:CompareDateTimeToBoolConverter />
</MultiBinding.Converter>
<Binding Mode="OneWay" Path="EstimatedEndLocal" />
<Binding
Mode="OneWay"
Path="Now"
Source="{StaticResource DateTimeNowTicker}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- EndedAtLocal column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding EndedAtLocal, Mode=OneWay, StringFormat='{}{0:dd.MM.yyyy HH:mm}'}"
FilterMemberPath="EndedAtLocal.Date"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderEndTime}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- RemindAtLocal column, röd om passerad -->
<telerik:GridViewDataColumn
DataMemberBinding="{Binding RemindAtLocal, Mode=OneWay, StringFormat='{}{0:dd.MM.yyyy HH:mm}'}"
FilterMemberPath="RemindAtLocal.Data"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderReminderTime}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding>
<MultiBinding.Converter>
<valueConverters:CompareDateTimeToBoolConverter />
</MultiBinding.Converter>
<Binding Mode="OneWay" Path="RemindAtLocal" />
<Binding
Mode="OneWay"
Path="Now"
Source="{StaticResource DateTimeNowTicker}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- PÃ¥minnelse ikon - datetimenow column -->
<telerik:GridViewDataColumn
x:Name="PaminnelseIkon"
CellStyle="{StaticResource IncidentListTextEffects}"
DataType="{x:Type system:Boolean}"
Header=""
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}"
SortMemberPath="RemindAtLocal">
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate>
<TextBlock
Margin="2,0"
Padding="0"
FontFamily="{StaticResource TelerikWebUI}"
Text="{StaticResource GlyphWarning}">
<TextBlock.Visibility>
<MultiBinding>
<MultiBinding.Converter>
<valueConverters:CompareDateTimeToVisibilityConverter />
</MultiBinding.Converter>
<Binding Mode="OneWay" Path="RemindAtLocal" />
<Binding
Mode="OneWay"
Path="Now"
Source="{StaticResource DateTimeNowTicker}" />
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
</telerik:GridViewDataColumn>
<!-- Traffic central namne column (east,west,north) -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_TC}"
IsReadOnly="True"
ToolTip="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_TrafficCentral}" />
<!-- TA-number (Trafficorder plan) column - source fifa -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_TA_Nr}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}"
ToolTip="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_TrafficOrderPlan}" />
<!-- Workingorder number column - source maximo -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_AO_Nr}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}"
ToolTip="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_WorkOrderNumber}" />
<!-- AlarmText column -->
<telerik:GridViewDataColumn
DataMemberBinding="{Binding AlarmText, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderAlarmText}"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}"
Style="{StaticResource LongTextColumnStyle}">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Setter Property="ToolTip" Value="{Binding AlarmText, Mode=OneWay}" />
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- AlarmCode column -->
<telerik:GridViewDataColumn
DataMemberBinding="{Binding AlarmCode, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderAlarmCode}"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}"
Style="{StaticResource LongTextColumnStyle}">
<telerik:GridViewDataColumn.CellStyle>
<Style BasedOn="{StaticResource IncidentListTextEffects}" TargetType="telerik:GridViewCell">
<Setter Property="ToolTip" Value="{Binding AlarmCode, Mode=OneWay}" />
</Style>
</telerik:GridViewDataColumn.CellStyle>
</telerik:GridViewDataColumn>
<!-- AlarmIsActive column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding AlarmIsActive, Mode=OneWay, Converter={StaticResource BoolToTextConverter}}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ColumnHeaderAlarmStatus}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- object/equipment (componentId) column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
DataMemberBinding="{Binding FacilityObjectId, Mode=OneWay}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_Equipment}"
IsReadOnly="True" />
<!-- Alternativename 3 for equipment of column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_ANV}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
<!-- raps-channel column -->
<telerik:GridViewDataColumn
CellStyle="{StaticResource IncidentListTextEffects}"
Header="{x:Static resx:Resources.Features_Incidents_Views_IncidentListView_RAPS}"
IsReadOnly="True"
IsVisible="{Binding IsTemplateList, Converter={StaticResource InvertBoolConverter}}" />
</telerik:RadGridView.Columns>
<!-- Setting up Context Menu On dataRows (and alternating rows) -->
<telerik:RadGridView.AlternateRowStyle>
<Style BasedOn="{StaticResource TelerikAlternatingRowsGreyWhiteSelectable}" TargetType="telerik:GridViewRow">
<!-- handles doublecklick on rows -->
<Setter Property="cal:Message.Attach" Value="[MouseDoubleClick] = [Action OpenIncident($dataContext)]" />
<!-- contextmenu is in own window, this to get access to lists datacontext from contextmenu -->
<Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType=views:IncidentListView}}" />
<Setter Property="ContextMenu" Value="{StaticResource IncidentGridContextMenu}" />
</Style>
</telerik:RadGridView.AlternateRowStyle>
<telerik:RadGridView.RowStyle>
<Style BasedOn="{StaticResource TelerikAlternatingRowsGreyWhiteSelectable}" TargetType="telerik:GridViewRow">
<!-- handles doublecklick on rows -->
<Setter Property="cal:Message.Attach" Value="[MouseDoubleClick] = [Action OpenIncident($dataContext)]" />
<!-- contextmenu is in own window, this to get access to lists datacontext from contextmenu -->
<Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType=views:IncidentListView}}" />
<Setter Property="ContextMenu" Value="{StaticResource IncidentGridContextMenu}" />
</Style>
</telerik:RadGridView.RowStyle>
</telerik:RadGridView>
And the QueryableCollectionView is created as follows:
private QueryableCollectionView _incidentListCollectionView;
Incidents = new ObservableCollection<IncidentItemViewModel>();
IncidentListCollectionView = GetInitializedIncidentCollectionView(Incidents);
private QueryableCollectionView GetInitializedIncidentCollectionView(INotifyCollectionChanged incidents)
{
var result = (ListCollectionView) CollectionViewSource.GetDefaultView(incidents);
result.CustomSort = new IncidentItemComparer();
result.Culture = CultureInfo.CurrentCulture;
var collectionViewLiveShaping = (ICollectionViewLiveShaping) result;
collectionViewLiveShaping.IsLiveSorting = true;
collectionViewLiveShaping.LiveSortingProperties.Add(nameof(IncidentItemViewModel.IncidentPriority));
collectionViewLiveShaping.LiveSortingProperties.Add(nameof(IncidentItemViewModel.NeedsAttention));
collectionViewLiveShaping.LiveSortingProperties.Add(nameof(IncidentItemViewModel.ConfirmedBy));
collectionViewLiveShaping.LiveSortingProperties.Add(nameof(IncidentItemViewModel.StartedAtLocal));
return new QueryableCollectionView(result);
}
Then the ObservableCollection "Incidents" are populated in the following function, where the input to the function is the return result from a module:
private void AddIncidentItemViewModelsFromResultToIncidents(IEnumerable<ListIncidentsResultItem> incidents)
{
var newViewModels = new List<IncidentItemViewModel>();
foreach (var incident in incidents)
{
var vm = ViewModelBuilder.Build<IncidentItemViewModel>(new
{
dto = incident,
isTemplateList = IsTemplateList
});
newViewModels.Add(vm);
}
foreach (var vm in newViewModels)
{
Incidents.Add(vm);
}
}
Everything until this point works fine. At this point though, the filters aren't added yet.
When a new incident is created the following code runs and adds a new item to the Incidents (ObservableCollection) array:
public void Handle(IncidentSaved message)
{
var incidentDto = message?.Incident;
var incidentId = incidentDto?.IncidentId;
var incident = Incidents.SingleOrDefault(i => i.Id == incidentId);
if (incident == null)
{
// New incident
var newIncidentModel = ViewModelBuilder.Build<IncidentItemViewModel>(new {incident = incidentDto});
Incidents.Add(newIncidentModel);
}
else
{
incident.SetIncidentDetails(incidentDto);
}
}
Hello Martin,
I've used the code to create a sample project, but I couldn't reproduce the issue. You can find my project attached here. I've stripped down a lot of the code because I don't have the related parts, so I will guess I am missing something. What I can suggest you is to open a new ticket from your telerik.com account an attach a runnable showing the issue there.
Regards,
Martin Ivanov
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.