WPF Datagrid DataGridTemplateColumn DataTemplate UserControl MVVM
//uercontrol <UserControl x:Class="WpfApp47.ImgTbk" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp47" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <Border Width="800" Height="500"> <Border.Background> <ImageBrush ImageSource="{Binding UCImgSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Stretch="Uniform" RenderOptions.BitmapScalingMode="Fant"/> </Border.Background> <TextBlock Text="{Binding UCStr,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Foreground="Red" FontSize="100" FontWeight="ExtraBold" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> </Grid> </UserControl> //call usercontrol in datagrid <DataGridTemplateColumn Header="Image"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <local:ImgTbk UCImgSource="{Binding DataContext.ImgSource, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}}}" UCStr="{Binding DataContext.ISBN, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}}}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns>
//usercontrol //xaml <UserControl x:Class="WpfApp47.ImgTbk" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp47" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <Border Width="800" Height="500"> <Border.Background> <ImageBrush ImageSource="{Binding UCImgSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Stretch="Uniform" RenderOptions.BitmapScalingMode="Fant"/> </Border.Background> <TextBlock Text="{Binding UCStr,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Foreground="Red" FontSize="100" FontWeight="ExtraBold" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> </Grid> </UserControl> //usercontrol.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; 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; namespace WpfApp47 { /// <summary> /// Interaction logic for ImgTbk.xaml /// </summary> public partial class ImgTbk : UserControl { public ImgTbk() { InitializeComponent(); this.DataContext = this; } public ImageSource UCImgSource { get { return (ImageSource)GetValue(ImgSourceProperty); } set { SetValue(ImgSourceProperty, value); } } // Using a DependencyProperty as the backing store for ImgSource. This enables animation, styling, binding, etc... public static readonly DependencyProperty ImgSourceProperty = DependencyProperty.Register("UCImgSource", typeof(ImageSource), typeof(ImgTbk), new PropertyMetadata(null)); public string UCStr { get { return (string)GetValue(UCStrProperty); } set { SetValue(UCStrProperty, value); } } // Using a DependencyProperty as the backing store for UCStr. This enables animation, styling, binding, etc... public static readonly DependencyProperty UCStrProperty = DependencyProperty.Register("UCStr", typeof(string), typeof(ImgTbk), new PropertyMetadata("")); } } //xaml <Window x:Class="WpfApp47.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" WindowState="Maximized" xmlns:local="clr-namespace:WpfApp47" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:BookVM/> </Window.DataContext> <Grid> <DataGrid ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedBk,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding SelectedIdx,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" CanUserAddRows="False" VirtualizingPanel.IsContainerVirtualizable="True" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.CacheLength="1" VirtualizingPanel.CacheLengthUnit="Item"> <DataGrid.Columns> <DataGridTemplateColumn Header="Id"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Id}" FontSize="100" Foreground="Red"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header="Image"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <local:ImgTbk UCImgSource="{Binding DataContext.ImgSource, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}}}" UCStr="{Binding DataContext.ISBN, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}}}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window> //xaml.cs using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Data.SqlTypes; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; 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; namespace WpfApp47 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class BookVM : INotifyPropertyChanged { public BookVM() { InitData(); } private void InitData() { var imgs = Directory.GetFiles(@"../../Images"); if (imgs != null && imgs.Any()) { imgsList = new List<string>(imgs); imgsCount=imgsList.Count; BooksCollection = new ObservableCollection<Book>(); for (int i = 0; i < 10000; i++) { BooksCollection.Add(new Book() { Id = i + 1, ISBN = $"ISBN_{i + 1}", ImgUrl = $"{imgsList[i % imgsCount]}", ImgSource = GetImageSourceViaUrl(imgs[i % imgsCount]) }); } } } private ImageSource GetImageSourceViaUrl(string imgUrl) { BitmapImage bmi = new BitmapImage(); bmi.BeginInit(); bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute); bmi.EndInit(); if (bmi.CanFreeze) { bmi.Freeze(); } return bmi; } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } private ObservableCollection<Book> booksCollection; public ObservableCollection<Book> BooksCollection { get { return booksCollection; } set { if (value != booksCollection) { booksCollection = value; OnPropertyChanged(nameof(BooksCollection)); } } } private Book selectedBk; public Book SelectedBk { get { return selectedBk; } set { if (value != selectedBk) { selectedBk = value; OnPropertyChanged(nameof(SelectedBk)); } } } private int selectedIdx; public int SelectedIdx { get { return selectedIdx; } set { if (value != selectedIdx) { selectedIdx = value; OnPropertyChanged(nameof(SelectedIdx)); } } } private List<string> imgsList { get; set; } private int imgsCount = 0; } public class Book { public int Id { get; set; } public string ISBN { get; set; } public string ImgUrl { get; set; } public ImageSource ImgSource { get; set; } } }