我正在开发一个C#WPF应用程序(在Windows上),我需要在运行时动态创建很多控件.由于应用程序的性质,我无法在WPF窗口的许多方面使用标准XAML(带模板).这是一个非常独特的案例,不,我不会重新考虑我的申请格式.
我想要完成的事情:
我想以编程方式创建一个控件,显示StackPanels(或任何其他有效的控件组)的可滚动列表,对于一个用例,每个控件都包含一个TextBlock控件顶部的Image控件(图片)(标题/标题) ):
>我更愿意在没有任何数据绑定的情况下完成所有这些操作(参见下面的推理).因为项目是在运行时定义的,所以我应该能够通过迭代在没有它们的情况下完成这项工作.
>控件/查看器应该能够有多个列/行,因此它不是一维的(就像典型的ListBox控件一样).
>它也应该可以互换,以便您可以修改(添加,删除等)控件中的项目.
我已经包含了一张图片(下图),为您提供了一个可能的用例示例.
在past中,我已经能够通过使用带有ItemTemplate(包装在ScrollViewer中)的ListView使用XAML来完成所有这些.但是,完全使用C#代码执行此操作会使其更加困难.我最近用普通的c#代码创建了ControlTemplates(使用FrameworkElementFactorys.它可能会有点复杂,我不确定它是不是最好的做法.我应该尝试使用相同的路径(使用带有模板的ListView)?如果是这样,怎么样?或者用C#代码实现更简单,更优雅的选项?
编辑:我真的不想使用任何数据绑定.我只想创建一个StackPanels的(可滚动的)列表,我可以轻松地修改/调整它.使用数据绑定感觉就像是向后实现,并且违背了运行时动态特性的目的.
编辑2(1/25/2018):回复不多.我只需要一个统一的,可滚动的stackpanel列表.我可以调整它以满足我的需求,但它需要全部用C#(代码隐藏).如果有人需要更多信息/澄清,请告诉我.谢谢.
解决方法
MoviePresenter.cs:
public class MoviePresenter : ListBox { public MoviePresenter() { FrameworkElementFactory factory = new FrameworkElementFactory(typeof(UniformGrid)); factory.SetBinding( UniformGrid.ColumnsProperty,new Binding(nameof(ActualWidth)) { Source = this,Mode = BindingMode.OneWay,Converter = new WidthToColumnsConverter() { ItemMinWidth = 100 } }); ItemsPanel = new ItemsPanelTemplate() { VisualTree = factory }; } } internal class WidthToColumnsConverter : IValueConverter { public double ItemMinWidth { get; set; } = 1; public object Convert(object value,Type targetType,object parameter,CultureInfo culture) { double? actualWidth = value as double?; if (!actualWidth.HasValue) return Binding.DoNothing; return Math.Max(1,Math.Floor(actualWidth.Value / ItemMinWidth)); } public object ConvertBack(object value,CultureInfo culture) { throw new NotImplementedException(); } }
MovieItem.cs:
public class MovieItem : Grid { public MovieItem() { RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); Image image = new Image(); image.Stretch = Stretch.UniformToFill; image.SetBinding(Image.SourceProperty,new Binding(nameof(ImageSource)) { Source = this }); Children.Add(image); TextBlock title = new TextBlock(); title.FontSize += 1; title.FontWeight = FontWeights.Bold; title.Foreground = Brushes.Beige; title.TextTrimming = TextTrimming.CharacterEllipsis; title.SetBinding(TextBlock.TextProperty,new Binding(nameof(Title)) { Source = this }); Grid.SetRow(title,1); Children.Add(title); TextBlock year = new TextBlock(); year.Foreground = Brushes.LightGray; year.TextTrimming = TextTrimming.CharacterEllipsis; year.SetBinding(TextBlock.TextProperty,new Binding(nameof(Year)) { Source = this }); Grid.SetRow(year,2); Children.Add(year); TextBlock releaseDate = new TextBlock(); releaseDate.Foreground = Brushes.LightGray; releaseDate.TextTrimming = TextTrimming.CharacterEllipsis; releaseDate.SetBinding(TextBlock.TextProperty,new Binding(nameof(ReleaseDate)) { Source = this }); Grid.SetRow(releaseDate,3); Children.Add(releaseDate); } public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource",typeof(string),typeof(MovieItem),new PropertyMetadata(null)); public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title",new PropertyMetadata(null)); public static readonly DependencyProperty YearProperty = DependencyProperty.Register("Year",new PropertyMetadata(null)); public static readonly DependencyProperty ReleaseDateProperty = DependencyProperty.Register("ReleaseDate",new PropertyMetadata(null)); public string ImageSource { get { return (string)GetValue(ImageSourceProperty); } set { SetValue(ImageSourceProperty,value); } } public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty,value); } } public string Year { get { return (string)GetValue(YearProperty); } set { SetValue(YearProperty,value); } } public string ReleaseDate { get { return (string)GetValue(ReleaseDateProperty); } set { SetValue(ReleaseDateProperty,value); } } }
MainWindow.xaml:
<Grid> <local:MoviePresenter x:Name="moviePresenter" ScrollViewer.HorizontalScrollBarVisibility="Disabled"/> </Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); for (int i = 0; i < 20; i++) { DateTime dummyDate = DateTime.Now.AddMonths(-i).AddDays(-(i * i)); MovieItem item = new MovieItem() { ImageSource = $"http://fakeimg.pl/100x200/?text=Image_{i}",Title = $"Dummy movie {i}",Year = $"{dummyDate.Year}",ReleaseDate = $"{dummyDate.ToLongDateString()}" }; moviePresenter.Items.Add(item); } } }