动态控件添加,基本UI开发都需要使用。我看过很多人写,都停留在WinFrom开发时代的直接操作控件来实现动态添加控件。到了WPF依然很多人在这样操作。
(不是说这样写错误,但是这违背了UI和逻辑分离的思想,不利于后期维护。深有体会。当看到后台密密麻麻的添加子控件,心情瞬间崩溃)
我们先来看下UI和逻辑不分离的代码(简单粗暴实现代码):
XAML代码:
<Window x:Class="WpfApplication4.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:WpfApplication4" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="60"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Button Content="Add" Width="50" Grid.Row="0" Click="Button_Click_1" /> <WrapPanel x:Name="wpContainer" Width="525" Height="300" Grid.Row="1"/> </Grid> </Window>
XAML.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 WpfApplication4 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { #region << Constructor >> public MainWindow() { InitializeComponent(); //this.DataContext = new MainWindowsViewModel(); } #endregion #region << Method >> private void Button_Click_1(object sender, RoutedEventArgs e) { this.wpContainer.Children.Add(GetChild("NewChild")); } private StackPanel GetChild(string name) { StackPanel container = new StackPanel(); container.Width = 300; container.Orientation = Orientation.Horizontal; TextBlock tb = new TextBlock(); tb.Width = 120; tb.Height = 60; tb.Margin = new Thickness(4, 4, 4, 4); tb.Text = name; Button btnRead = new Button(); btnRead.Content = "Read"; btnRead.Width = 80; btnRead.Height = 60; btnRead.Margin = new Thickness(4, 4, 4, 4); Button btnWrite = new Button(); btnWrite.Content = "Write"; btnWrite.Width = 80; btnWrite.Height = 60; btnWrite.Margin = new Thickness(4, 4, 4, 4); container.Children.Add(tb); container.Children.Add(btnRead); container.Children.Add(btnWrite); return container; } #endregion } }
上面的实现动态添加控件。我直接使用路由事件(我可不想把控件传到ViewModel中,所以没用Command)
只是简单的添加,不调整布局,无样式。就有许多代码了。当我们动态添加的控件过于复杂。或者前台美工想调整布局。觉得是灾难;
下面是我们使用下DataTemplate的动态添加控件。(容器使用ListView.容器样式默认(只是为了实现动态,不关心样式))
XAML代码:
<Window x:Class="WpfApplication4.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:local="clr-namespace:WpfApplication4" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <DataTemplate x:Key="itemTemplate"> <StackPanel Orientation="Horizontal"> <TextBlock Text="NewChild" Width="120" Height="60" Margin="4,4,4,4"/> <Button Content="Read" Width="80" Height="60" Margin="4,4,4,4"/> <Button Content="Write" Width="80" Height="60" Margin="4,4,4,4"/> </StackPanel> </DataTemplate> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="60"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Button Content="Add" Width="50" Grid.Row="0" Command="{Binding ClickCommand}"/> <ListView x:Name="wpContainer" Width="525" Height="300" Grid.Row="1" ItemTemplate="{StaticResource ResourceKey=itemTemplate}" ItemsSource="{Binding ItemList}" /> </Grid> </Window>
XAML.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 WpfApplication4 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { #region << Constructor >> public MainWindow() { InitializeComponent(); this.DataContext = new MainWindowsViewModel(); } #endregion } }
后台代码很干净
ViewModel代码:
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; namespace WpfApplication4 { public class MainWindowsViewModel:NotifyObject { #region << Property >> public ObservableCollection<string> ItemList { get; set; } public ICommand ClickCommand { get; set; } #endregion #region << Constructor >> public MainWindowsViewModel() { ItemList = new ObservableCollection<string>(); ClickCommand = new DeletegateCommand(Click); } #endregion #region << Method >> public void Click() { ItemList.Add("xx"); } #endregion } }
ViewModel代码也很干净。
相对来说,很多的代码都移到了前台页面中。所有逻辑层的代码相对来说较少。
动态添加 只要有ItemTemplate属性的控件都可以使用。(基本上)
这样写的话,主要任务就交给了美观(LIstView样式的调整)