在wpf中我想把下面XMAL代码转换为C#后台代码,请问如何实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在wpf中我想把下面XMAL代码转换为C#后台代码,请问如何实现相关的知识,希望对你有一定的参考价值。

<Button Content="执行" Margin="521,559,15,12">
<i:Interaction.Behaviors>
<tt:ToolTipBehavior Category="Informational">
<local:MyToolTipContent/>
</tt:ToolTipBehavior>
</i:Interaction.Behaviors>
</Button>

通过Itemontrol,ListBox,ListView等控件都能动态生成子元素。

下面是转换示例代码:

            Button btn = new Button();
            ToolTipBehavior behavior = new ToolTipBehavior();
            behavior.Category = "Informational";
            Interaction.GetBehaviors(btn).Add(behavior);
参考技术A 为什么要转成后台代码,后台代码写起来更复杂。追问

因为我要动态生成控件

追答

试问怎么样的动态,有无规则,如果是一个有序的控件组,那用ItemsControl结合上述button作为Template也是动态。

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

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

01

功能演示

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 


            

以上是关于在wpf中我想把下面XMAL代码转换为C#后台代码,请问如何实现的主要内容,如果未能解决你的问题,请参考以下文章

做WPF页面的时候我想通过C#代码触发自定义控件中的事件怎么做

WPF中style中定义的控件如何里面包含一个checkbox控件,我想在后台c#代码中使用该控件,代码如何写?

WPF C# 实现鼠标穿透窗体

wpf中我自定义了一个自定义控件,add到了界面,如何设置显示在最底层?后台代码如何控制?

如何将 C# 代码转换为 Kotlin 由 Json 库组成

C# WPF从后台代码生成行列可变的表格