I’ve spent the last few days tracking down how to get a ListView to refresh its associated generic list collection which is populated via LINQ to SQL. My UI is more complex than the below example, but you’ll get the idea. I essentially wanted a ListView that gets populated from a LINQ to SQL object. As the binding is occurring, I want it to check to see if the transaction has been voided. If it has, I want it to disable the Void button. I do this check view an IValueConverter. This was working, but after clicking on an unvoided transaction, the button’s IsEnabled property wasn’t changing. And after reading many posts, ranging from using ObservableCollections to changing the ListView.DataContext to changing the ListView.ItemsSource of the list, I still wasn’t able to find a simple solution to my seemingly simple problem.
After much trial and error - I thought I’d share with the world what I did to remedy it:
The XAML
MyWindow.xaml
...
<Window.CommandBindings>
<CommandBinding Command="{x:Static MyWindow.VoidTransactionCommand}"
Executed="VoidTransaction" />
</Window.CommandBindings>
...
<ListView Margin="0,0,0,0" Name="myList" FontSize="10" FontFamily="Tahoma"
Height="189"
Width="585">
<ListView.View>
<GridView>
<GridViewColumn Header="ID#"
DisplayMemberBinding="{Binding Path=ID}" />
<GridViewColumn Header="Voided?">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Void"
IsEnabled="{Binding Path=IsVoided, Converter={StaticResource oppositeBooleanConverter}}"
Command="{x:Static MyWindow.VoidTransactionCommand}"
CommandParameter="{Binding Path=ID}">
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
...
Teh Code
MyWindow.CodeBehind
...
private SomeDataContext db = new SomeDataContext(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
private List<SomeObject> privateList;
...
public static RoutedCommand VoidTransactionCommand = new RoutedCommand();
private void VoidTransaction(object sender, ExecutedRoutedEventArgs args)
{
bool wasSuccess = insert some method that voids the transaction;
if (!wasSuccess)
{
MessageBox.Show("This transaction could not be voided.");
} else
{
db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, privateList);
ICollectionView view = CollectionViewSource.GetDefaultView(myList.ItemsSource);
view.Refresh();
}
}
OppositeBooleanConverter.cs
public class OppositeBooleanConverter : IValueConverter {
public object Convert(object value, Type targetType, object
parameter, System.Globalization.CultureInfo culture)
{
try
{
return !(bool)value;
} catch {}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return null;
}
}
The Solution
Above in blue, you’ll notice that I call the DataContext.Refresh() method. And since it is overriden by the web method that I call in my implementation, I don’t want the UI to update the database, so I have the RefreshMode.OverwriteCurrentValues of the window-level field privateList. This will reset the data, but then you need to get a reference to the ICollectionView of the ListView.ItemsSource and call the Refresh() method of that, thereby loading your refreshed data into the view.