菲佣WPF——4(关于DataTemplate(2)动态控件添加神器)

 

动态控件添加,基本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样式的调整)

 

 

 

posted @ 2013-02-15 15:56  qiurideyun  阅读(735)  评论(0编辑  收藏  举报