public static ObservableCollection<Book> DeserializeXmlDocument(XmlDocument xmlDoc)
{
try
{
using var xmlReader = new XmlNodeReader(xmlDoc);
var serializer = new DataContractSerializer(typeof(List<Book>));
var bksList = (List<Book>)serializer.ReadObject(xmlReader);
return new ObservableCollection<Book>(bksList);
}
catch (Exception ex)
{
MessageBox.Show(ex?.Message);
return new ObservableCollection<Book>();
}
}
<Window x:Class="WpfApp18.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp18"
mc:Ignorable="d"
Title="{Binding MainTitle}" WindowState="Maximized">
<Window.DataContext>
<local:MainVM/>
</Window.DataContext>
<Window.Resources>
<local:LenConverter x:Key="LenConverter"/>
<DataTemplate DataType="{x:Type local:Book}"
x:Key="DGDataTemplate">
<Border BorderBrush="LightBlue"
BorderThickness="2"
Margin="5"
Width="{Binding Source={x:Static SystemParameters.FullPrimaryScreenWidth},
Converter={StaticResource LenConverter},ConverterParameter=3}"
Height="{Binding Source={x:Static SystemParameters.FullPrimaryScreenHeight},
Converter={StaticResource LenConverter},ConverterParameter=3}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="30"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Id}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding Comment}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Content}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding Author}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding CategoryName}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding Summary}"/>
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding Title}"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="{Binding Topic}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding ISBN}"/>
</Grid>
</Border>
</DataTemplate>
<ControlTemplate x:Key="DGControlTemplate" TargetType="ContentControl">
<DataGrid ItemsSource="{Binding Books}"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
VirtualizingPanel.CacheLength="5,5"
VirtualizingPanel.CacheLengthUnit="Item"
ScrollViewer.CanContentScroll="True"
ScrollViewer.IsDeferredScrollingEnabled="False"
AutoGenerateColumns="False"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<Binding Source="{StaticResource DGDataTemplate}"/>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ControlTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0"
Template="{StaticResource DGControlTemplate}"/>
<ContentControl Grid.Column="1"
Template="{StaticResource DGControlTemplate}"/>
<ContentControl Grid.Column="2"
Template="{StaticResource DGControlTemplate}"/>
</Grid>
</Window>
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
namespace WpfApp18
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MainVM : INotifyPropertyChanged
{
private HttpClient client;
string originUrl = @"http://localhost:54941/BookService.svc/getbooks?cnt=";
bool isLoading = false;
public MainVM()
{
if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
client = new HttpClient();
_= InitBooksAsync(1000000);
}
}
private async Task InitBooksAsync(int cnt=1000000)
{
await Task.Run(async() =>
{
if(isLoading)
{
return;
}
isLoading = true;
try
{
string xmlStr = await client.GetStringAsync($"{originUrl}{cnt}");
SetMainTitle($"Downloading from server finished");
if (!string.IsNullOrWhiteSpace(xmlStr))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlStr);
await Application.Current?.Dispatcher?.InvokeAsync(() =>
{
var bks = XmlHelper.DeserializeXmlDocument(xmlDoc);
Books = new ObservableCollection<Book>(bks);
SetMainTitle($"FirstId:{Books.FirstOrDefault()?.Id},LastId:{Books?.LastOrDefault()?.Id}");
//Books = new ObservableCollection<Book>(XmlHelper.GetBooksFromXmlDocument(xmlDoc));
}, System.Windows.Threading.DispatcherPriority.Background);
}
}
catch (Exception ex)
{
PrintMsg(ex?.Message);
isLoading = false;
}
finally
{
isLoading = false;
}
});
}
private void SetMainTitle(string msg)
{
Application.Current?.Dispatcher.InvokeAsync(() =>
{
MainTitle=$"{DateTime.Now.ToString("yyyyMMddHHmmssffff")},{msg}";
},System.Windows.Threading.DispatcherPriority.Background);
}
private void PrintMsg(string msg)
{
#if DEBUG
System.Diagnostics.Debug.WriteLine($"{DateTime.Now},{msg}");
#else
System.Diagnostics.Trace.WriteLine($"{DateTime.Now},msg");
#endif
}
private string mainTitle = $"{DateTime.Now.ToString("yyyyMMddHHmmssffff")}";
public string MainTitle
{
get
{
return mainTitle;
}
set
{
if(value!=mainTitle)
{
mainTitle = value;
OnPropertyChanged();
}
}
}
private ObservableCollection<Book> books;
public ObservableCollection<Book> Books
{
get
{
return books;
}
set
{
if(value!=books)
{
books = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propName="")
{
var handler=Volatile.Read(ref this.PropertyChanged);
if(handler==null)
{
return;
}
handler.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class LenConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(double.TryParse(value?.ToString(),out double d) && double.TryParse(parameter?.ToString(),out double p) && p>0.0)
{
return d / p;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class XmlHelper
{
public static ObservableCollection<Book> GetBooksFromXmlDocument(XmlDocument xmlDoc)
{
var result = new ObservableCollection<Book>();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
string ns = "http://schemas.datacontract.org/2004/07/WcfService8";
nsmgr.AddNamespace("dc", ns);
XmlNodeList bookNodes = xmlDoc.SelectNodes("//dc:Book", nsmgr);
if(bookNodes==null || bookNodes.Count==0)
{
return result;
}
foreach(XmlNode bkNode in bookNodes)
{
Book bk = new Book();
bk.Id = long.TryParse(GetNodeText(bkNode, "dc:Id", nsmgr), out long idVal) ? idVal : 0;
bk.Name = GetNodeText(bkNode, "dc:Name", nsmgr);
bk.ISBN = GetNodeText(bkNode, "dc:ISBN", nsmgr);
bk.Comment = GetNodeText(bkNode, "dc:Comment", nsmgr);
bk.Content = GetNodeText(bkNode, "dc:Content", nsmgr);
bk.Author = GetNodeText(bkNode, "dc:Author", nsmgr);
bk.CategoryName = GetNodeText(bkNode, "dc:CategoryName", nsmgr);
bk.Summary = GetNodeText(bkNode, "dc:Summary", nsmgr);
bk.Title = GetNodeText(bkNode, "dc:Title", nsmgr);
bk.Topic = GetNodeText(bkNode, "dc:Topic", nsmgr);
result.Add(bk);
}
return result;
}
private static string GetNodeText(XmlNode bkNode, string xPath, XmlNamespaceManager nsmgr)
{
XmlNode child = bkNode.SelectSingleNode(xPath, nsmgr);
return child?.InnerText ?? string.Empty;
}
public static ObservableCollection<Book> DeserializeXmlDocument(XmlDocument xmlDoc)
{
try
{
using var xmlReader = new XmlNodeReader(xmlDoc);
var serializer = new DataContractSerializer(typeof(List<Book>));
var bksList = (List<Book>)serializer.ReadObject(xmlReader);
return new ObservableCollection<Book>(bksList);
}
catch (Exception ex)
{
MessageBox.Show(ex?.Message);
return new ObservableCollection<Book>();
}
}
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/WcfService8")]
public class Book
{
[DataMember]
public long Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string ISBN { get; set; }
[DataMember]
public string Comment { get; set; }
[DataMember]
public string Content { get; set; }
[DataMember]
public string Author { get; set; }
[DataMember]
public string CategoryName { get; set; }
[DataMember]
public string Summary { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Topic { get; set; }
}
}
![image]()
![image]()
//D:\C\WcfService8\WcfService8\IBookService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfService8
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IBookService" in both code and config file together.
[ServiceContract]
public interface IBookService
{
[OperationContract]
[WebGet(UriTemplate="/getbooks?cnt={cnt}")]
List<Book> GetBooks(int cnt);
}
public class Book
{
public long Id { get; set; }
public string Name { get; set; }
public string ISBN { get; set; }
public string Comment { get; set; }
public string Content { get; set; }
public string Author { get; set; }
public string CategoryName { get; set; }
public string Summary { get; set; }
public string Title { get; set; }
public string Topic { get; set; }
}
enum BookCategoryEnum
{
Science,
Technology,
Engineering,
Math
}
}
//D:\C\WcfService8\WcfService8\BookService.svc.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Syndication;
using System.Text;
using System.Threading;
namespace WcfService8
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "BookService" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select BookService.svc or BookService.svc.cs at the Solution Explorer and start debugging.
public class BookService : IBookService
{
static string[] enumNames = Enum.GetNames(typeof(BookCategoryEnum));
static Random rnd = new Random();
static int enumNamesCnt = enumNames.Length;
private static long id = 1;
private static (long, long) GetStartEnd(long interval)
{
long end = Interlocked.Add(ref id, interval);
long start = end - interval;
return (start, end);
}
public List<Book> GetBooks(int cnt)
{
var (start, end) = GetStartEnd((long)cnt);
var bks = new List<Book>(cnt);
for(long i= start; i < end; i++)
{
bks.Add(new Book()
{
Id = i,
Name = $"Name_{i}",
ISBN = $"ISBN_{i}_{Guid.NewGuid():N}",
Comment = $"Comment_{i}",
Content = $"Content_{i}",
Summary = $"Summary_{i}",
Title = $"Title_{i}",
Topic = $"Topic_{i}",
Author = $"Author_{i}",
CategoryName = enumNames[rnd.Next(0,enumNamesCnt)]
});
}
string msg = $"Start:{start},End:{end},interval:{cnt}";
PrintMsg(msg);
return bks;
}
private void PrintMsg(string msg)
{
#if DEBUG
System.Diagnostics.Debug.WriteLine($"{DateTime.Now},{msg}");
#else
System.Diagnostics.Trace.WriteLine($"{DateTime.Now},msg");
#endif
}
}
}
//D:\C\WcfService8\WcfService8\Web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.8" />
<httpRuntime targetFramework="4.8"/>
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="BookServiceWebHttpBinding"
openTimeout="01:00:00"
closeTimeout="01:00:00"
sendTimeout="01:00:00"
receiveTimeout="01:00:00"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxDepth="2147483647"
maxNameTableCharCount="2147483647"
maxStringContentLength="2147483647"/>
<security mode="None"/>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="BookServiceBehavior">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="BookServiceEndPointBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="WcfService8.BookService"
behaviorConfiguration="BookServiceBehavior">
<endpoint address=""
binding="webHttpBinding"
contract="WcfService8.IBookService"
behaviorConfiguration="BookServiceEndPointBehavior"
bindingConfiguration="BookServiceWebHttpBinding"/>
</service>
</services>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>