如何在WPF中动态向WrapPanel添加预制Material Design Card?
动态添加预定义Material Design Card到WrapPanel的解决方案
嘿,我之前也碰到过一模一样的需求——不想在代码里手动拼所有子控件,只想把现成的Card像单个控件一样丢进WrapPanel里。这里有几个靠谱的方法,你可以根据自己的场景选:
方法1:把Card封装成UserControl(最推荐!)
这是最省心的方式,把你的Card做成独立的UserControl,之后用起来就和普通Button没区别:
创建UserControl
新建一个UserControl(比如叫PDFThumbnailCard.xaml),把你的Card代码直接搬进去就行,我还给子控件加了名字方便后续操作:<UserControl x:Class="YourProjectNamespace.PDFThumbnailCard" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"> <materialDesign:Card Margin="3,3,0,0" Width="200"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="140" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <!-- 给Image加名字,方便后续设置预览图 --> <Image x:Name="PreviewImage" Height="140" Width="196" Stretch="UniformToFill" /> <StackPanel HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal" Margin="8"> <!-- 给Delete按钮加名字,方便绑定点击事件 --> <Button x:Name="DeleteBtn" Style="{StaticResource MaterialDesignToolButton}" Width="30" Padding="2 0 2 0" materialDesign:RippleAssist.IsCentered="True"> <materialDesign:PackIcon Kind="Delete" /> </Button> </StackPanel> </Grid> </materialDesign:Card> </UserControl>代码里动态添加
现在你可以像实例化普通控件一样创建这个Card,然后直接丢进WrapPanel:// 新建一个Card实例 var newPdfCard = new PDFThumbnailCard(); // 给预览图设置图片源 newPdfCard.PreviewImage.Source = new BitmapImage(new Uri("你的PDF预览图路径")); // 绑定删除按钮的点击事件 newPdfCard.DeleteBtn.Click += (s, e) => { /* 这里写删除逻辑 */ }; // 加到WrapPanel里 yourWrapPanel.Children.Add(newPdfCard);
方法2:用XAML资源+克隆实例(不用新建UserControl)
如果你不想额外创建UserControl,也可以把Card作为资源,然后每次获取新实例添加:
在Resources里定义Card
注意要加x:Shared="False",这样每次取资源都会返回新的实例,不会重复用同一个:<Window.Resources> <materialDesign:Card x:Key="PDFThumbnailTemplate" x:Shared="False" Margin="3,3,0,0" Width="200"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="140" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Image x:Name="PreviewImage" Height="140" Width="196" Stretch="UniformToFill" /> <StackPanel HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal" Margin="8"> <Button Style="{StaticResource MaterialDesignToolButton}" Width="30" Padding="2 0 2 0" materialDesign:RippleAssist.IsCentered="True"> <materialDesign:PackIcon Kind="Delete" /> </Button> </StackPanel> </Grid> </materialDesign:Card> </Window.Resources>代码里获取并添加
// 从资源里拿到新的Card实例 var pdfCard = FindResource("PDFThumbnailTemplate") as MaterialDesignThemes.Wpf.Card; // 如果要修改子控件,比如设置预览图 if (pdfCard?.FindName("PreviewImage") is Image previewImg) { previewImg.Source = new BitmapImage(new Uri("你的预览图路径")); } // 加到WrapPanel yourWrapPanel.Children.Add(pdfCard);
方法3:用ItemsControl绑定数据(批量添加更优雅)
如果你要一次性加很多Card,用MVVM的方式绑定数据会更清爽:
定义DataTemplate
<Window.Resources> <DataTemplate x:Key="PDFThumbnailTemplate"> <materialDesign:Card Margin="3,3,0,0" Width="200"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="140" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <!-- 绑定ViewModel里的预览图路径 --> <Image Height="140" Width="196" Stretch="UniformToFill" Source="{Binding PreviewPath}" /> <StackPanel HorizontalAlignment="Right" Grid.Row="2" Orientation="Horizontal" Margin="8"> <!-- 绑定删除命令 --> <Button Style="{StaticResource MaterialDesignToolButton}" Width="30" Padding="2 0 2 0" materialDesign:RippleAssist.IsCentered="True" Command="{Binding DeleteCommand}" CommandParameter="{Binding}"> <materialDesign:PackIcon Kind="Delete" /> </Button> </StackPanel> </Grid> </materialDesign:Card> </DataTemplate> </Window.Resources>用ItemsControl替代手动添加
把WrapPanel作为ItemsControl的布局容器,然后绑定数据源:<ItemsControl ItemsSource="{Binding YourPDFItemCollection}" ItemTemplate="{StaticResource PDFThumbnailTemplate}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl>之后你只需要在ViewModel里维护一个
ObservableCollection<PDFItem>,往里面加数据,Card就会自动生成并显示在WrapPanel里啦。
内容的提问来源于stack exchange,提问作者Emre Kadan
相关产品推荐
相关产品推荐

