I would like to use a CollectionView of items in the view to real-time update based on a remote XML file.
I am using an ObservableCollection because it is fast. I have a large list of 25,000 records and have other code that will be running in each parallel thread that should take 1 second for each, hence why I chose to parallel
ServerList.cs
[Serializable]
public class ServerList
{
[Serializable]
public class ServerList
{
public List<Server> Servers { get; set; }
}
[Serializable]
public class Server
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Phone { get; set; }
[XmlIgnore]
public string FullName { get; set; }
}
}
ListViewModel.cs
// constructors
public ServerList.Server ServerListViewItem;
private ObservableCollection<ServerList.Server> serverListViewItem;
public ObservableCollection<ServerList> ServerListView
{
get
{
return serverListView;
}
set
{
this.serverListView = value;
this.RaisePropertyChanged("serverListView");
}
}
public ServerList serverList { get; set; }
// load list of servers from XML and parse into collection
this.serverList = new ServerList();
this.ServerListView = new ListCollectionView(new List<ServerList>());
XmlDocument xmlFetch = new XmlDocument();
xmlFetch.LoadXml(new WebClient().DownloadString("http://domain.com/pathto.xml"));
XmlNode xmlNode = xmlFetch;
XmlReader xmlReader = new XmlNodeReader(xmlNode);
XmlSerializer mySerializer = new XmlSerializer(typeof(ServerList));
this.serverList = (ServerList)mySerializer.Deserialize(xmlReader);
// parallel method should update UI as results are finished
private void LoadAll()
{
Parallel.ForEach(
this.serverList,
new ParallelOptions { MaxDegreeOfParallelism = 25 },
row =>
{
this.ServerListViewItem = new ServerList.Server();
string fullName = row.FirstName + " " + row.LastName;
this.ServerListViewItem.FullName = fullName;
this.ServerListViewItem.FirstName = FirstName;
this.ServerListViewItem.LastName = LastName;
this.ServerListViewItem.Phone = Phone;
ServerListView.Add(ServerListViewItem); // problematic!
}
);
}
// allow usage of the UI while parallel thread is running
Thread ParallelProcessThread = new Thread(this.LoadAll);
ParallelProcessThread.Start();
List.xaml
<UserControl.Resources>
<Style x:Key="lvStyle" TargetType="{x:Type ListView}">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="True"/>
<Setter Property="ListView.ItemsSource" Value="{Binding Path=ServerListView}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="#202020" />
<Setter Property="ListView.View">
<Setter.Value>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="FullName" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="FirstName" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="LastName" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding LastName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Phone" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Phone}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsLoading}" Value="True">
<Setter Property="ListView.Cursor" Value="Wait"/>
<Setter Property="ListView.Background" Value="LightGray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
.. the call in List.xaml
<ListView Style="{DynamicResource lvStyle}" />
I get this error:
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.