WPF parse xml via [XmRoot] and [XmlElement] attributes together, contentcontrol's template is ControlTemplate from Resources

//This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ArrayOfBook xmlns="http://schemas.datacontract.org/2004/07/WcfService3" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Book>
<CategoryName>Engineering</CategoryName>
<Comment>Comment_4020611</Comment>
<ISBN>ISBN_4020611_873618a856b04c7186dbe2a60eb0a218</ISBN>
<Id>4020611</Id>
<Name>Name_4020611</Name>
</Book>
<Book>
<CategoryName>Engineering</CategoryName>
<Comment>Comment_4020612</Comment>
<ISBN>ISBN_4020612_bf13765c127042f99615207c5fd00953</ISBN>
<Id>4020612</Id>
<Name>Name_4020612</Name>
</Book>
</ArrayOfBook>

image

 

 

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 CategoryName { get; set; }
}

[XmlRoot("ArrayOfBook", Namespace = "http://schemas.datacontract.org/2004/07/WcfService3")]
public class XmlBook
{
    [XmlElement(nameof(Book))]
    public List<Book> BksList { get; set; }
}

 private List<Book> XmlSerializerDeserializeXmlStr(string xmlStr)
 {
     var serializer = new XmlSerializer(typeof(XmlBook));
     using (var reader = new StringReader(xmlStr))
     {
         var xmlBook = (XmlBook)serializer.Deserialize(reader);
         if (xmlBook != null && xmlBook.BksList != null && xmlBook.BksList.Any())
         {
             return xmlBook.BksList;
         }
     }
     return null;
 }

 

//xaml
<Window x:Class="WpfApp6.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:WpfApp6"
        mc:Ignorable="d"
        Title="MainWindow"
        WindowState="Maximized">
    <Window.DataContext>
        <local:MainVM/>
    </Window.DataContext>

    <Window.Resources>

        <Style TargetType="TextBlock" x:Key="TbkStyle">
            <Setter Property="FontSize" Value="30"/>
            <Setter Property="FontWeight" Value="Normal"/>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Foreground" Value="Red"/>
                    <Setter Property="FontWeight" Value="Bold"/>
                </Trigger>
            </Style.Triggers>
        </Style>

        <DataTemplate DataType="{x:Type local:Book}"
                      x:Key="RowDataTemplate">
            <Border BorderBrush="LightGray" 
                    BorderThickness="1"
                    Margin="3">
                <Grid Margin="3">
                    <Grid.Resources>
                        <Style TargetType="TextBlock" BasedOn="{StaticResource TbkStyle}"/>
                    </Grid.Resources>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="0"/>
                    <TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/>
                    <TextBlock Text="{Binding CategoryName}" Grid.Row="1" Grid.Column="0"/>
                    <TextBlock Text="{Binding Comment}" Grid.Row="1" Grid.Column="1"/>
                    <TextBlock Text="{Binding ISBN}" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"/>
                </Grid>
            </Border>
        </DataTemplate>

        <ControlTemplate TargetType="ContentControl" x:Key="ContentControlTemplate">
            <ScrollViewer>
                <ItemsControl ItemsSource="{Binding Books}"
                          ItemTemplate="{StaticResource RowDataTemplate}"
                          Margin="5"
                          VirtualizingPanel.IsVirtualizing="True"
                          VirtualizingPanel.VirtualizationMode="Recycling"
                          VirtualizingPanel.CacheLength="5,5"
                          VirtualizingPanel.CacheLengthUnit="Item"
                          ScrollViewer.CanContentScroll="True"
                          ScrollViewer.IsDeferredScrollingEnabled="True"
                          UseLayoutRounding="True"
                          SnapsToDevicePixels="True">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </ScrollViewer>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <ContentControl Template="{StaticResource ContentControlTemplate}"/>
    </Grid>
</Window>


//cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Runtime.CompilerServices;
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.Serialization;

namespace WpfApp6
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Closed += MainWindow_Closed;
        }

        private void MainWindow_Closed(object? sender, EventArgs e)
        {
            var vm = this.DataContext as MainVM;
            if(vm!=null)
            {
                vm.Dispose();
            }
        }
    }

    public class MainVM : INotifyPropertyChanged, IDisposable
    {
        private bool _isDisposed = false;
        private CancellationTokenSource _cts = new CancellationTokenSource();
        private Task _loadTask;
        private string originUrl = "http://localhost:57995/BookService.svc/getbooks?cnt=";
        private HttpClient client = new HttpClient();
        public MainVM()
        {
            if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                _loadTask = LoadDataAsync(100, _cts.Token);
            }
        }

        private async Task LoadDataAsync(int cnt = 10000, CancellationToken token = default)
        {
            if (_cts.IsCancellationRequested)
            {
                return;
            }

            try
            {
                string url = $"{originUrl}{cnt}";
                string xmlStr = await client.GetStringAsync(url);
                var bksList = XmlSerializerDeserializeXmlStr(xmlStr);
                if (bksList != null && bksList.Any())
                {
                    if(token.IsCancellationRequested)
                    {
                        return;
                    }
                    await Application.Current?.Dispatcher?.InvokeAsync(() =>
                    {
                        Books = new ObservableCollection<Book>(bksList);
                    }, System.Windows.Threading.DispatcherPriority.Background);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex?.Message);
                return;
            }
        }

        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 PropertyChanged);
            if (handler == null)
            {
                return;
            }
            handler?.Invoke(this, new PropertyChangedEventArgs(propName));
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool isDisposing)
        {
            if (_isDisposed)
            {
                return;
            }

            if (isDisposing)
            {
                _cts = null;
                client = null;
                _isDisposed = true;
            }
        }

        private List<Book> XmlSerializerDeserializeXmlStr(string xmlStr)
        {
            var serializer = new XmlSerializer(typeof(XmlBook));
            using (var reader = new StringReader(xmlStr))
            {
                var xmlBook = (XmlBook)serializer.Deserialize(reader);
                if (xmlBook != null && xmlBook.BksList != null && xmlBook.BksList.Any())
                {
                    return xmlBook.BksList;
                }
            }
            return null;
        }
    }

    [XmlRoot("ArrayOfBook", Namespace = "http://schemas.datacontract.org/2004/07/WcfService3")]
    public class XmlBook
    {
        [XmlElement(nameof(Book))]
        public List<Book> BksList { get; set; }
    }

    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 CategoryName { get; set; }
    }
}

 

 

 

 

 

 

 

 

 

 

image

 

 

 

image

 

posted @ 2026-07-26 21:08  FredGrit  阅读(1)  评论(0)    收藏  举报