WPF中基于数据库记录数动态生成Material Design卡片的技术实现问询
WPF中基于数据库记录数动态生成Material Design卡片的技术实现问询
嘿,我完全懂你现在的需求啦——你想让WPF界面里的Material Design卡片能跟着数据库里的记录数量自动生成,每张卡片对应一条数据,把数据库里的图片和文本都显示出来对吧?别担心,咱们一步步来搞定这个问题:
第一步:先定义对应数据库记录的数据模型
首先得创建一个类来映射数据库里的每条记录,这样咱们才能把数据库的数据转换成WPF能识别的对象。这个类需要实现INotifyPropertyChanged接口,这样数据更新时界面能自动同步:
using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Media; public class CardItem : INotifyPropertyChanged { private string _title; private string _description; private ImageSource _imageSource; public string Title { get => _title; set { _title = value; OnPropertyChanged(); } } public string Description { get => _description; set { _description = value; OnPropertyChanged(); } } public ImageSource ImageSource { get => _imageSource; set { _imageSource = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
第二步:在ViewModel里准备数据集合
接下来需要一个能自动通知界面变化的集合(推荐用ObservableCollection<T>)来存放所有从数据库读取的卡片数据,然后写个方法把数据库里的记录转换成CardItem对象加进去:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Media.Imaging; using System; public class MainViewModel : INotifyPropertyChanged { public ObservableCollection<CardItem> CardItems { get; set; } public MainViewModel() { CardItems = new ObservableCollection<CardItem>(); // 初始化时加载数据库数据 LoadCardDataFromDatabase(); } private void LoadCardDataFromDatabase() { // 这里替换成你实际的数据库查询逻辑 // 示例:假设你已经有方法从数据库获取记录列表 var dbRecords = GetRecordsFromDatabase(); foreach (var record in dbRecords) { var cardItem = new CardItem { Title = record.Title, Description = record.Description, // 如果数据库存的是图片路径,直接转成ImageSource ImageSource = new BitmapImage(new Uri(record.ImagePath, UriKind.RelativeOrAbsolute)) }; CardItems.Add(cardItem); } } // 你需要自己实现这个方法,从数据库读取记录 private IEnumerable<YourDbRecordType> GetRecordsFromDatabase() { // 这里写你的数据库查询代码,比如用EF Core或者ADO.NET // 返回数据库里的记录集合 } // 实现INotifyPropertyChanged接口,和上面CardItem的逻辑一样 public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
第三步:修改XAML,用ItemsControl动态生成卡片
你原来的代码是手动写了一堆重复的Card,现在咱们把这些手动代码换成ItemsControl,让它自动根据集合里的CardItem生成卡片:
<StackPanel Grid.Row="1"> <hc:SearchBar hc:InfoElement.Placeholder="Search" hc:InfoElement.TitlePlacement="Left" Style="{StaticResource SearchBarExtend}" Margin="20 0 125 20" /> <materialDesign:Card Margin="20 0 125 20"> <StackPanel> <TextBlock Text="Categories" FontSize="28" FontWeight="400" /> <TextBlock Text="Самые распространенные и часто выбираемые архитекрурные решения зданий" FontSize="14" FontWeight="200" /> <hc:ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden" IsInertiaEnabled="True"> <!-- 用ItemsControl绑定CardItems集合 --> <ItemsControl ItemsSource="{Binding CardItems}"> <!-- 指定卡片的布局容器为WrapPanel --> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal" Margin="0 20 0 0"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <!-- 定义单张卡片的模板,绑定CardItem的属性 --> <ItemsControl.ItemTemplate> <DataTemplate> <materialDesign:Card Margin="15 0 15 0 "> <StackPanel Height="200" Width="200"> <Image Source="{Binding ImageSource}"/> <TextBlock FontSize="18" FontWeight="Medium" Text="{Binding Title}" /> <TextBlock FontSize="15" FontWeight="Regular" Text="{Binding Description}" /> </StackPanel> </materialDesign:Card> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </hc:ScrollViewer> </StackPanel> </materialDesign:Card> </StackPanel>
第四步:关联ViewModel和View
最后要把ViewModel设置为界面的DataContext,这样XAML里的绑定才能生效。比如在Window的构造函数里:
public MainWindow() { InitializeComponent(); // 设置DataContext为ViewModel实例 DataContext = new MainViewModel(); }
额外注意点
- 如果数据库里存储的是图片的二进制数据(不是路径),需要把byte[]转换成ImageSource,示例代码如下:
// 假设record.ImageData是数据库里的二进制图片 byte[] imageBytes = record.ImageData; using (var ms = new MemoryStream(imageBytes)) { var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.StreamSource = ms; bitmap.EndInit(); cardItem.ImageSource = bitmap; }
- 确保你的XAML顶部已经正确引用了Material Design和HandyControl的命名空间:
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:hc="https://handyorg.github.io/handycontrol"
备注:内容来源于stack exchange,提问作者Fainer Game
相关产品推荐
相关产品推荐

