zoukankan      html  css  js  c++  java
  • WPF:理解ContentControl——动态添加控件和查找控件

    WPF:理解ContentControl——动态添加控件和查找控件

    我认为WPF的核心改变之一就是控件模型发生了重要的变化,大的方面说,现在窗口中的控件(大部分)都没有独立的Hwnd了。而且控件可以通过所谓的模板提供各种各样的表现形式。

    这一篇就来谈一谈ContentControl,的第一部分,动态添加控件和查找控件

    什么是ContentControl呢?其实WPF的绝大部分的控件,还包括窗口本身都是继承自ContentControl的。

     

    有的时候,我们需要在窗口出来之后,再动态添加一些控件。例如一个最简单的场景:我们需要做一个扫雷程序,该扫雷程序根据用户选择的难易程度决定要显示多少个地雷。

    为了便于理解,大家可以看下面这三个图片

    image

    image

    image 

    ok,我们还是回想一下在Windows Forms里面怎么做?

    using System;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                //初级版,实例化6*6一共64个按钮
                CreateButton(6, 6);
            }
    
    
    
            private void button2_Click(object sender, EventArgs e)
            {
                //高级版,实例化9*9一共81个按钮
                CreateButton(9, 9);
            }
    
            private void CreateButton(int x, int y) {
                panel1.SuspendLayout();
                panel1.Controls.Clear();
    
                //四个方向的边距都是5
                int width = (panel1.Width-(x+1)*5)/x;
                int height = (panel1.Height-(y+1)*5)/y;
    
    
    
    
                for (int i = 0; i < x; i++)
                {
                    for (int j = 0; j < y; j++)
                    {
                        Button bt = new Button()
                        {
                            Width = width,
                            Height = height,
                            Left = i*width+5,
                            Top = j*height+5
                        };
    
                        panel1.Controls.Add(bt);
                        
                    }
                }
    
                panel1.ResumeLayout();
            }
    
    
        }
    }
    

    我们可以花一点点时间稍微解释一下,其实我们就是用循环的方式,动态地创建了一批按钮出来,然后将他们添加到Panel的Controls集合中去。

    那么,同样的思路放在WPF中来是否可行呢?我们一步一步来看吧

    首先,在WPF中进行布局控制有几个主要的容器

    • Canvas是按照绝对位置定位的,很像上面的Panel这种机制;
    • StackPanel呢,则是基于流模式的,它没有绝对定位的概念,一批控件要么从左到右排列,要么从上而下排列
    • Grid,可能是用的最多的,它可以提供按照行和列的方式更好地组织控件。而事实上,在Grid里面也可以嵌入Canvas和StackPanel,他们结合可以构造出足够复杂的 界面。

     

    那么,我们就来尝试用Canvas实现与Windows Forms类似的效果吧

    image

    image

    image

    那么,我们的代码有什么区别呢?

    第一部分是XAML代码

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="我的扫雷程序" Height="516" Width="592">
        <Grid>
            <Button Height="23" HorizontalAlignment="Left" Margin="20,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click">初级</Button>
            <Button Height="23" HorizontalAlignment="Left" Margin="101,12,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click">高级</Button>
            <Canvas Margin="20,41,12,12" Name="canvas1"  />
        </Grid>
    </Window>
    

    第二部分是C#代码

    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Window1.xaml 的交互逻辑
        /// </summary>
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                CreateButton(6, 6);
            }
    
    
            private void button2_Click(object sender, RoutedEventArgs e)
            {
                CreateButton(9, 9);
            }
    
            private void CreateButton(int x, int y)
            {
                
    
    
                canvas1.Children.Clear();
    
                //四个方向的边距都是5
                double width = (this.canvas1.ActualWidth - (x + 1) * 5) / x;
                double height = (this.canvas1.ActualHeight - (y + 1) * 5) / y;
    
    
    
    
                for (int i = 0; i < x; i++)
                {
                    for (int j = 0; j < y; j++)
                    {
                        Button bt = new Button()
                        {
                            Width = width,
                            Height = height
                        };
    
                        Canvas.SetTop(bt, j * height + 5);
                        Canvas.SetLeft(bt, i * width + 5);
                        //这两句很关键。按钮在Canvas中的定位与它自己的Left以及Top不是一个概念
                        
    
                        canvas1.Children.Add(bt);
                        
                        
                    }
                }
    
                
            }
    
    
        }
    }
    

    我们发现了以下区别

    1. 现在没有Controls这个概念了,而是有一个Children属性,代表了所有的子内容

    2.针对不同的容器,有一些特殊的方法来定位子元素。例如Canvas的SetTop等方法 。

  • 相关阅读:
    windows的80端口被占用时的处理方法
    Ansible自动化运维工具安装与使用实例
    Tomcat的测试网页换成自己项目首页
    LeetCode 219. Contains Duplicate II
    LeetCode Contest 177
    LeetCode 217. Contains Duplicate
    LeetCode 216. Combination Sum III(DFS)
    LeetCode 215. Kth Largest Element in an Array(排序)
    Contest 176 LeetCode 1354. Construct Target Array With Multiple Sums(优先队列,递推)
    Contest 176
  • 原文地址:https://www.cnblogs.com/kevinGao/p/4188734.html
Copyright © 2011-2022 走看看