现在有这么一个需求,需要动态添加自定义控件到界面,自定义控件数量不固定,内容是通过服务获取的,以前是做winform的,winform简单,直接 new自定义控件添加上去就行,现在wpf mvvm模式,不知道怎么做了,能否在viewmodel中添加一个 observablecollection,界面绑定这个属性,界面自动生成这么多个自定义控件?如果可以,各位大佬能否提供下实现思路,有个demo什 么的最好了。
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<!--控件模板-->
<DataTemplate x:Key="UserDataTemplate">
<Border BorderThickness="2" BorderBrush="Black" Margin="2">
<StackPanel>
<Image />
<Label HorizontalAlignment="Center" Content="{Binding Path=Name}" />
</StackPanel>
</Border>
</DataTemplate>
</Window.Resources>
<Grid Name="mygrid">
<!--容器-->
<ItemsControl x:Name="testList" ItemTemplate="{StaticResource UserDataTemplate}" ItemsSource="{Binding Btns}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Window>
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 WpfApplication5
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindowViewModel user { get; set; }
public MainWindow()
{
InitializeComponent();
user = new MainWindowViewModel();
mygrid.DataContext = user;//指定ViewModel
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace WpfApplication5
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MainWindowViewModel()
{
Btns = new ObservableCollection<Item>() { new Item(){Name = "测试1"}, new Item(){Name = "测试2"} };
}
private ObservableCollection<Item> btns;
public ObservableCollection<Item> Btns
{
get { return btns; }
set { btns = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication5
{
public class Item : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
}
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:WpfApp1"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate DataType="{x:Type local:MyContract}"> <!-- 类型是MyContract的,用这个模板 -->
<StackPanel Width="128" Height="150" Margin="20">
<Image Source="{Binding ImageUrl}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:MyCard}"><!-- 类型是MyCard的,用这个模板 -->
<Grid Width="128" Height="150" Margin="20" Background="{Binding Color}">
<TextBlock Text="{Binding Color}" FontSize="24" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Items}" > <!-- 不直接指定模板,而是用数据类型来决定 -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel IsItemsHost="True" /></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Window>
using System.Collections.ObjectModel;
using System.Windows;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Items = new ObservableCollection<object>()
{
new MyContract(){ Name = "杀马特丶蛮牛", ImageUrl = "https://profile.csdnimg.cn/A/3/4/1_zhengbingfe"},
new MyContract(){ Name = "正怒月神", ImageUrl = "https://profile.csdnimg.cn/F/F/E/1_hanjun0612"},
new MyContract(){ Name = "OrdinaryCoder", ImageUrl = "https://profile.csdnimg.cn/6/0/9/1_weixin_40440974"},
new MyCard() { Color = "PeachPuff"},
new MyCard() { Color = "SeaShell"},
new MyCard() { Color = "SteelBlue"},
};
this.DataContext = this;
}
public ObservableCollection<object> Items { get; }
}
public class MyContract // 可自行实现INotifyPropertyChanged接口
{
public string Name { get; set; }
public string ImageUrl { get; set; }
}
public class MyCard
{
public string Color { get; set; }
}
}
另外,数据模板的强处,在于它可以利用数据类型,来决定具体的展示模板。