Keep same selected Item in a ListView when the collection it is bound to is refreshed
I have a ListView that is bound to an ObservableCollection which is itself derived from an IQueryable. When I refresh the collection, after items are added, edited or a button is clicked (to see if the database has new items from other users). The listbox refreshes and selects the first item in the collection.
I want to keep the same selected item (If it still exists) after a refresh but because the Collection has been replaced I cannot seem to compare equality between an item in the old collection and the new one. All attemtps never have a match.
How should this be done?
Below are some relevant code snipets if anyone wants to see them:
The ListView, MouseDoubleClick Event opens an edit window
<ListView x:Name="IssueListView"
ItemsSource="{Binding Issues}"
ItemTemplate="{StaticResource ShowIssueDetail}"
IsSynchronizedWithCurrentItem="True"
MouseDoubleClick="IssueListView_MouseDoubleClick" />
It's DataTemplate
<DataTemplate x:Key="ShowIssueDetail">
<Border CornerRadius="3" Margin="2" MinWidth="400" BorderThickness="2"
BorderBrush="{Binding Path=IssUrgency,
Converter={StaticResource IntToRYGBBorderBrushConverter}}">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=IssSubject}"
Margin="3" FontWeight="Bold" FontSize="14"/>
<!--DataTrigger will collapse following panel for simple view-->
<StackPanel Name="IssueDetailPanel" Visibility="Visible" Margin="3">
<StackPanel Width="Auto" Orientation="Horizontal">
<TextBlock Text="Due: " FontWeight="Bold"/>
<TextBlock Text="{Binding Path=IssDueDate, StringFormat='d'}"
FontStyle="Italic" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel Width="Auto" Orientation="Horizontal">
<TextBlock Text="Category: " FontWeight="Bold"/>
<TextBlock Text="{Binding Path=IssCategory}"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataT开发者_如何学Crigger Binding="{Binding Path=StatusBoardViewModel.ShowDetailListItems,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}" Value="False">
<Setter TargetName="IssueDetailPanel"
Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
The Issues collection is refreshed by executing a QueryIssues Method that builds a Linq To SQL query programatically based on bound controls. IssuesQuery is an IQueryable property
public void QueryIssues()
{
// Will show all items
IssuesQuery = from i in db.Issues
orderby i.IssDueDate, i.IssUrgency
select i;
// Filters out closed issues if they are not to be shown
if (includeClosedIssues == false)
{
IssuesQuery = from i in IssuesQuery
where i.IssIsClosed == false
select i;
}
// Filters out Regular Tasks if they are not to be shown
if (showTasks == false)
{
IssuesQuery = from i in IssuesQuery
where i.IssIsOnStatusBoard == true
select i;
}
// Filters out private items if they are not to be shown
if (showPrivateIssues == false)
{
IssuesQuery = from i in IssuesQuery
where i.IssIsPrivate == false
select i;
}
// Filters out Deaprtments if one is selected
if (departmentToShow != "All")
{
IssuesQuery = from i in IssuesQuery
where i.IssDepartment == departmentToShow
select i;
}
Issues = new ObservableCollection<Issue>(IssuesQuery);
}
Because you are getting completely new objects there is no other way to match equality than to find the item that matches the old (if it exists) and select it. You are replacing your collection which means that you have to track the selected item yourself.
Other options:
You could keep a collection and manually add/remove items based on the query results (ie don't destroy the current item).
One way to do this in your view model:
// The ListView's SelectedItem is bound to CurrentlySelectedItem
var selectedItem = this.CurrentlySelectedItem;
// ListView is bound to the Collection property
// setting Collection automatically raises an INotifyPropertyChanged notification
this.Collection = GetIssues(); // load collection with new data
this.CurrentlySelectedItem = this.Collection.SingleOrDefault<Issue>(x => x.Id == selectedItem.Id);
When faced with this issue in the past i have wrapped the items i want to display in a small view model class, then given each an extra property IsSelected and then bound this property to the ListBoxItem using an ItemContainerStyle. That way i keep track of what is selected.
精彩评论