C# WPF后台代码动态添加控件

在wpf开发中,虽然可以通过XMAL编写炫酷的界面,但是有时候需要动态定义控件即:前台界面控件数量或者类型需要解析的数据或者其它条件确认再生成,这时候我们就需要通过后台cs中编写代码实现这一功能。

01

功能演示

eb97f1c5643c118e2b3837540250c636.gif

02


功能说明

以上演示部分我们可以看到我前台的部分界面在窗体加载后并没有显示,而是选择文件解析后自动产生的,这种场景有时候也挺常用,特别是有大量同类型的数据显示到同类型的控件中时,我们就可以通过导入txt、Xml等文件的形式然后自动生成. 本地主要是举例演示实现这一功能,使用场景造得可能并不恰当,大家忍受下。

03


源码实现

前台代码:

<UserControl x:Class="Caliburn.Micro.Hello.DynamicalView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Caliburn.Micro.Hello" 
             xmlns:cal="http://www.caliburnproject.org" xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1.5*" />
            <RowDefinition Height="8.5*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Grid.Row="0" Grid.ColumnSpan="2">
            <TextBox Width="500" Height="30"  Margin="3" Text="{Binding FilePath}" FontSize="14" 
                             FontStyle="Normal" IsReadOnly="True" />
            <Button  Content="..." Margin="3" MinWidth="50"
                    cal:Message.Attach="[Event Click] = [Action SelectFile()]" />
        </StackPanel>
        <GroupBox Grid.Column="0" Grid.Row="1" Margin="3">
            <GroupBox.Header>
                <dxlc:LayoutItem Label="Student" Foreground ="Green" />
            </GroupBox.Header>
            <dxlc:LayoutControl>
                <Grid  HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="0"
                                     cal:Message.Attach="[Event Loaded] = [Action StudentGridLoaded($source)]" />
            </dxlc:LayoutControl>
        </GroupBox>
        <GroupBox Grid.Column="1" Grid.Row="1" Margin="3">
            <GroupBox.Header>
                <dxlc:LayoutItem Label="Teacher" Foreground ="Blue" />
            </GroupBox.Header>
            <dxlc:LayoutControl>
                <Grid  HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="0"
                                     cal:Message.Attach="[Event Loaded] = [Action TeacherGridLoaded($source)]" />
            </dxlc:LayoutControl>
        </GroupBox>
    </Grid>
</UserControl>

这里使用了Caliburn.Micro框架,所以需要引用名称空间

xmlns:cal="http://www.caliburnproject.org"

因为控件数量不确定,需要显示不全时行列可以拖动,实现这一功能只需要把控件包裹进:<dxlc:LayoutControl>就可以。

后台代码:

using DevExpress.Xpf.Editors;
using PropertyChanged;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Forms;
using Binding = System.Windows.Data.Binding;
using HorizontalAlignment = System.Windows.HorizontalAlignment;
using Label = System.Windows.Controls.Label;


namespace Caliburn.Micro.Hello
{
    [AddINotifyPropertyChangedInterface]
    public class DynamicalViewModel : Screen, IViewModel
    {
        private readonly AutoResetEvent StudentGridLoad = new AutoResetEvent(false);


        private readonly AutoResetEvent TeacherGridLoad = new AutoResetEvent(false);
        public string FilePath { get; set; } = @"D:\test.txt";
        public List<PersonInfoDTO> PersonInfoList = new List<PersonInfoDTO>();
        public PersonInfo PersonInfo { get; set; }
        public DynamicalViewModel()
        {
            DisplayName = "DynamicalControls";
        }


        public void DispalyReuslt()
        {
            Task.Run(() =>
                        {
                            ParseData();
                            Execute.OnUIThread(() =>
                            {
                                AddGridControl();
                            });
                        });


        }


        private void ParseData()
        {
            var lines = File.ReadAllLines(FilePath);
            foreach (string line in lines)
            {
                var strs = line.Split(':');
                if (strs.Count() > 1)
                {
                    var infos = strs[1].Split(',');
                    PersonInfoList.Add(new PersonInfoDTO()
                    {
                        InfoType = strs[0],
                        PersonInfo = new PersonInfo()
                        {
                            Name = infos[0],
                            Sex = infos[1],
                            Age = Convert.ToInt32(infos[2])
                        }
                    });
                }
            }
        }




        public void SelectFile()
        {
            string defaultInputFolder = @"D:\test.txt";
            OpenFileDialog fileDialog = new OpenFileDialog();
            if (defaultInputFolder != null)
            {
                fileDialog.InitialDirectory = defaultInputFolder;
            }


            fileDialog.Multiselect = false;//该值确定是否可以选择多个文件
            fileDialog.Title = "请选择ReportFile文件";
            fileDialog.Filter = "文本文件(*.txt)|*.txt";
            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                FilePath = fileDialog.FileName;
            }
            DispalyReuslt();
        }


        private Grid StudentGrid { get; set; }
        private Grid TeacherGrid { get; set; }
        public void StudentGridLoaded(object sender)
        {
            StudentGrid = (Grid)sender;
        }
        public void TeacherGridLoaded(object sender)
        {
            TeacherGrid = (Grid)sender;
        }


        int studentRowIndex = 0;
        int studentColumnIndex = 0;
        int teacherRowIndex = 0;
        int teacherColumnIndex = 0;
        private void AddGridControl()
        {
            int StudentConut = 0;
            int TeacherCount = 0;


            foreach (var item in PersonInfoList)
            {
                if (item.InfoType == "老师")
                {
                    TeacherCount++;
                }
                else
                {
                    StudentConut++;
                }
            }


            StudentGrid.Children.Clear();
            StudentGrid.ColumnDefinitions.Clear();
            StudentGrid.RowDefinitions.Clear();


            TeacherGrid.Children.Clear();
            TeacherGrid.ColumnDefinitions.Clear();
            TeacherGrid.RowDefinitions.Clear();


            var gridColumns = 4;
            var successGridRows = Math.Ceiling(StudentConut / 2.0);
            var failGridRows = Math.Ceiling(TeacherCount / 2.0);


            //添加grid列
            for (int i = 0; i < gridColumns; i++)
            {
                var successColumnDefinition = new ColumnDefinition();
                StudentGrid.ColumnDefinitions.Add(successColumnDefinition);
                var failedColumnDefinition = new ColumnDefinition();
                TeacherGrid.ColumnDefinitions.Add(failedColumnDefinition);
            }




            //添加grid行
            for (int i = 0; i < successGridRows; i++)
            {
                var successRowDefinition = new RowDefinition();
                StudentGrid.RowDefinitions.Add(successRowDefinition);
                successRowDefinition.Height = new GridLength(30, GridUnitType.Pixel);//绝对尺寸
            }


            for (int i = 0; i <= failGridRows; i++)
            {
                var failedRowDefinition = new RowDefinition();
                TeacherGrid.RowDefinitions.Add(failedRowDefinition);
                failedRowDefinition.Height = new GridLength(30, GridUnitType.Pixel);//绝对尺寸
            }


            int rowIndex = 0;
            int columnIndex = 0;
            UIElement uIElement = new UIElement();


            foreach (var item in PersonInfoList)
            {
                if (item.InfoType == "学生")
                {
                    if (studentColumnIndex / 4 == 1)
                    {
                        studentColumnIndex = 0;
                        studentRowIndex++;
                    }
                    rowIndex = studentRowIndex;
                    columnIndex = studentColumnIndex;
                }
                else
                {
                    if (teacherColumnIndex / 4 == 1)
                    {
                        teacherColumnIndex = 0;
                        teacherRowIndex++;
                    }
                    rowIndex = teacherRowIndex;
                    columnIndex = teacherColumnIndex;
                }


                if (columnIndex % 2 == 0)
                {
                    Label label = new Label();
                    label.HorizontalAlignment = HorizontalAlignment.Right;
                    label.VerticalAlignment = VerticalAlignment.Center;
                    label.Width = 100;
                    label.Content = item.PersonInfo.Name;
                    label.SetValue(Grid.RowProperty, rowIndex);
                    label.SetValue(Grid.ColumnProperty, columnIndex);


                    uIElement = label;
                    if (item.InfoType == "学生")
                    {
                        StudentGrid.Children.Add(uIElement);
                        studentColumnIndex++;
                        columnIndex = studentColumnIndex;
                    }
                    else
                    {
                        TeacherGrid.Children.Add(uIElement);
                        teacherColumnIndex++;
                        columnIndex = teacherColumnIndex;
                    }
                }


                TextEdit textBox = new TextEdit();
                textBox.HorizontalAlignment = HorizontalAlignment.Left;
                textBox.VerticalAlignment = VerticalAlignment.Center;
                textBox.Name = item.PersonInfo.Name;
                textBox.Width = 100;
                textBox.Height = 25;
                textBox.SetValue(Grid.RowProperty, rowIndex);
                textBox.SetValue(Grid.ColumnProperty, columnIndex);


                var path = item.PersonInfo.GetType().GetProperty("Age");
                Binding binding = new Binding()
                {
                    Source = item.PersonInfo,
                    Path = new PropertyPath(path),
                    Mode = BindingMode.TwoWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                };
                textBox.SetBinding(TextEdit.TextProperty, binding);
                uIElement = textBox;




                if (item.InfoType == "学生")
                {
                    StudentGrid.Children.Add(uIElement);
                    studentColumnIndex++;
                    columnIndex = studentColumnIndex;
                }
                else
                {
                    TeacherGrid.Children.Add(uIElement);
                    teacherColumnIndex++;
                    columnIndex = teacherColumnIndex;
                }
            }
        }


    }
}

数据模型:

public class PersonInfo
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Sex { get; set; }


        public override string ToString()
        {
            string report = $"[Name] = [{Name}],[Age] = [{Age}],[Sex] = [{Sex}]";
            return report;
        }


    }
    public class PersonInfoEven : PersonInfo
    {


    }


    public class PersonInfoDTO
    {
        public string InfoType { get; set; }
        public PersonInfo PersonInfo { get; set; }
    }

这里需要注意一些地方:

①首先StudentGridLoaded和TeacherGridLoaded是在viewmodel初始化完成后才加载的,所以在构造函数执行完后还是null;

②加载控件和解析数据比较慢我放在了线程Task.Run运行,但是线程中更新界面又需要用委托实现,这里CM给我们封装了方法

Execute.OnUIThread(() =>    { });

③:grid行列添加:

var successColumnDefinition = new ColumnDefinition();                
 StudentGrid.ColumnDefinitions.Add(successColumnDefinition);




 var successRowDefinition = new RowDefinition();
                StudentGrid.RowDefinitions.Add(successRowDefinition);

④通过代码生成TextEdit,bing数据并添加到grid中:

TextEdit textBox = new TextEdit();
                textBox.HorizontalAlignment = HorizontalAlignment.Left;
                textBox.VerticalAlignment = VerticalAlignment.Center;
                textBox.Name = item.PersonInfo.Name;
                textBox.Width = 100;
                textBox.Height = 25;
                textBox.SetValue(Grid.RowProperty, rowIndex);
                textBox.SetValue(Grid.ColumnProperty, columnIndex);


                var path = item.PersonInfo.GetType().GetProperty("Age");
                Binding binding = new Binding()
                {
                    Source = item.PersonInfo,
                    Path = new PropertyPath(path),
                    Mode = BindingMode.TwoWay,
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                };
                textBox.SetBinding(TextEdit.TextProperty, binding);
                uIElement = textBox;
                 TeacherGrid.Children.Add(uIElement);

⑤遍历grid中的控件:

foreach (UIElement uiElement in failedParsedGrid.Children)
            {
                if (uiElement is TextEdit)
                {
                    TextEdit textBox = uiElement as TextEdit;
                    switch (textBox.Name)
                    {
                    //todo
                    }
                    }
                    }

⑥通过反射遍历属性:

foreach (PropertyInfo info in PersonInfo.GetType().GetProperties())


            {


                var itemValue = info.GetValue(PersonInfo);


               // TO DO 


            }
### 回答1: 在WPF中,要在后台数据中添加控件,可以使用动态生成的方式。 首先,需要创建一个控件的实例,例如,可以创建一个Button或者TextBox的实例。然后,设置控件的属性,例如设置控件的文本、大小、位置等。接着,将控件添加到窗口中。 以下是一个示例代码: ``` Button btn = new Button(); btn.Content = "点击我"; btn.Width = 100; btn.Height = 30; btn.Margin = new Thickness(10, 10, 0, 0); this.Content = btn; ``` 在上述代码中,首先创建了一个Button的实例btn。然后,设置了按钮的文本为“点击我”,宽度为100,高度为30,以及位置为(10, 10)。最后,将按钮添加到窗口中,通过设置窗口的Content属性为按钮实例。 通过类似的方式,可以在后台数据中动态生成多个控件,并设置它们的属性。将它们添加到窗口中即可。这样,就实现了在后台数据添加控件的功能。 ### 回答2: 在WPF中,可以通过后台代码动态添加控件。以下是一个简单示例: 首先,在XAML文件中,我们可以定义一个用于容纳新控件的容器,例如一个StackPanel: <StackPanel x:Name="container"></StackPanel> 接下来,在后台代码中,我们可以使用C#语言动态创建控件实例,并将其添加到容器中。例如,我们可以创建一个Button控件实例并将其添加到StackPanel中: Button button = new Button(); button.Content = "点击我"; container.Children.Add(button); 在此示例中,我们创建了一个Button控件实例,并将其内容设置为“点击我”。然后,我们使用`container.Children.Add`方法将Button控件添加到StackPanel容器中。 通过这种方式,我们可以通过在后台代码动态创建控件实例,并将其添加到适当的容器中来实现添加控件的功能。 需要注意的是,这只是一个简单示例,实际应用中可能需要根据具体需求来进行更复杂的处理。例如,可能需要通过用户输入来动态生成控件,或者根据数据绑定来动态修改控件的属性等等。具体实现的复杂程度取决于需求和项目的具体情况。 ### 回答3: 在WPF中,可以通过后台数据源的绑定来实现动态添加控件。 首先,需要创建一个数据源,可以是一个集合类(如List或ObservableCollection)或数据库中的数据表。接着,将该数据源与控件的ItemsSource属性进行绑定,这样就能自动将数据源中的数据绑定到控件上。 然后,需要在XAML中定义一个控件模板,用于展示数据源中的每一项数据。可以使用DataTemplate标签定义模板,并在其中添加需要展示的控件,通过绑定数据的方式来显示每个控件的值。 接下来,在后台代码中,通过数据源的Add方法或数据库的插入语句,将新的数据项添加到数据源中。这样,控件就会自动根据绑定关系动态添加新的控件,并根据数据源中的值进行展示。 总结来说,通过后台数据源的绑定,可以实现在WPF动态添加控件。首先,创建一个数据源,并将其与控件的ItemsSource属性进行绑定。然后,在XAML中定义控件模板,用于展示数据源中的每一项数据。最后,在后台代码中,通过添加数据到数据源中,实现动态添加控件的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值