从FlowLayoutPanel中选择UserControl [英] Select UserControl from FlowLayoutPanel

查看:143
本文介绍了从FlowLayoutPanel中选择UserControl的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已在此问题的帮助下在FlowPanelLayout中设置了UserControls: 对于每个数据表,将UserControl添加到FlowLayoutPanel

我现在正在尝试实现一个单击事件,该事件使我可以在已选择的UserControl周围放置一个边框.我已经做到了:

        private void User_Load(object sender, EventArgs e)
    {
        flowlayoutpanelUsers.HorizontalScroll.Visible = false;

        // Load and Sort Users DataTable
        DataTable datatableUsers = UserMethods.GetUsers().Tables["Users"];
        datatableUsers.DefaultView.Sort = "Name";
        DataView dataviewUsers = datatableUsers.DefaultView;

        // Loop Through Rows and Add UsersGrid to FlowLayoutPael
        foreach (DataRowView datarowviewUsers in dataviewUsers)
        {
            var UsersGrid = new UsersGrid
            {
                Username = datarowviewUsers["Username"].ToString(),
                User = datarowviewUsers["Name"].ToString(),
                Admin = datarowviewUsers["Administrator"].ToString(),
            };
            flowlayoutpanelUsers.Controls.Add(UsersGrid);
            UsersGrid.MouseClick += new MouseEventHandler(user_click);
        }
    }

    private UsersGrid selectedUser;

    void user_click(object sender, EventArgs e)
    {
        if (selectedUser != null)
            selectedUser.BorderStyle = BorderStyle.None;
        selectedUser = (UsersGrid)sender;
        selectedUser.BorderStyle = BorderStyle.FixedSingle;
    }

我的问题是,仅当我在UserControl中单击空白时,它才起作用,而当用户单击两个标签或图像时,则不起作用.如何使它也适用于所有子对象?

然后,我该如何使用选定的UserControl进行其他操作,例如打开显示该选定用户的所有详细信息的表单?

解决方案

我为您提供了一些建议.在回应的底部,我包含了演示我的建议的代码.

建议1:在UC中修复MouseClick
当您为UserControl(UC)注册MouseClick事件时,您是为UserControl本身注册的,而不是为您放置在UserControl上的任何控件(如标签等)注册的.如果单击这些子控件中的一个,则单击将赢得不会被基础的UC看到".

要解决此问题,请为您的所有子控件注册MouseClick事件;您甚至可以为UserControl本身注册相同的MouseClick事件处理程序.

建议2:设置UC的BorderStyle
我将把用于设置UC BorderStyle的代码移到UC本身中.创建选择UC时设置为true的公共属性IsSelected.在属性的设置器中,根据属性的值更新UC的BorderStyle属性.

为您的UC公开一个IsSelected属性很方便:您可以查询一组这些UC以查看选择了哪些UC,而不是像通过Form级别变量那样尝试在控件外部跟踪此状态./p>

根据您的评论进行
这是一个示例,说明如何在FlowLayoutPanel中查询UC,以查看是否选择了UC,以及是否找到了可以采取某些措施的方法.在这种情况下,操作是调用EditUser方法,该方法将您从所选UC中的属性获取的参数值用作参数:

var selectedUC = flowLayoutPanel.Controls.Cast<UserControl1>().FirstOrDefault(uc => uc.IsSelected);
if (selectedUC != null) {
    // Use the properties of the UC found to be selected as parameters is method EditUser.
    EditUser(selectedUC.Name, selectedUC.Username, selectedUC.Administrator);
}

建议3:在一组UC中管理选择
如果要取消选择组中除用户单击(即选择)之外的所有UC,则需要在UC中创建一个事件,该事件在单击UC时触发.此事件的处理程序针对集合中的所有UC(例如在诸如Form,FlowLayoutPanel等容器类型控件中)的所有UC显式地将IsSelected设置为false,然后单击UC中的MouseClick处理程序,然后将其设置为false.点击UC的IsSelected变为true.

值得考虑创建另一个 UserControl类型来管理一组UC.这个新的UserControl可以封装用于创建和设置UC集的状态的代码,并且可以方便地在其他项目中使用您的UC,并使托管您的UC的窗体代码更加简洁.


我发现,与其为我的每个建议提供一系列不连贯的代码段,我希望包含的是我希望能够再现您所讨论内容的最小代码量.

创建一个新的Visual Studio Winform项目,并将以下内容用于类Form1:

public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();

        flowLayoutPanel = new FlowLayoutPanel {
            Dock = DockStyle.Fill,
        };
        this.Controls.Add(flowLayoutPanel);
        // Add several sample UCs.
        for (int i = 0; i < 10; i++) {
            var uc = new UserControl1();
            uc.WasClicked += UsersGrid_WasClicked;
            flowLayoutPanel.Controls.Add(uc);
        }
    }

    FlowLayoutPanel flowLayoutPanel;

    // Event handler for when MouseClick is raised in a UserControl.
    void UsersGrid_WasClicked(object sender, EventArgs e) {
        // Set IsSelected for all UCs in the FlowLayoutPanel to false. 
        foreach (Control c in flowLayoutPanel.Controls) {
            if (c is UserControl1) {
                ((UserControl1)c).IsSelected = false;
            }
        }
    }
}

接下来,将一个UserControl添加到项目中.保留名称UserControl1并添加几个Labels和一个PictureBox.将此代码用于类UserControl1:

public partial class UserControl1 : UserControl
{
    public UserControl1() {
        InitializeComponent();
        this.Load += UsersGrid_Load;
    }

    // Event fires when the MouseClick event fires for the UC or any of its child controls.
    public event EventHandler<EventArgs> WasClicked;

    private void UsersGrid_Load(object sender, EventArgs e) {
        // Register the MouseClick event with the UC's surface.
        this.MouseClick += Control_MouseClick;
        // Register MouseClick with all child controls.
        foreach (Control control in Controls) {
            control.MouseClick += Control_MouseClick;
        }
    }

    private void Control_MouseClick(object sender, MouseEventArgs e) {
        var wasClicked = WasClicked;
        if (wasClicked != null) {
            WasClicked(this, EventArgs.Empty);
        }
         // Select this UC on click.
         IsSelected = true;
    }

    private bool _isSelected;
    public bool IsSelected {
        get { return _isSelected; }
        set {
            _isSelected = value;
            this.BorderStyle = IsSelected ? BorderStyle.Fixed3D : BorderStyle.None;
        }
    }
}

I have set up UserControls in a FlowPanelLayout with the help in this question: For Each DataTable Add UserControl to FlowLayoutPanel

I am now trying to implement a click event which allows me to put a border around the UserControl that has been selected. I have done this:

        private void User_Load(object sender, EventArgs e)
    {
        flowlayoutpanelUsers.HorizontalScroll.Visible = false;

        // Load and Sort Users DataTable
        DataTable datatableUsers = UserMethods.GetUsers().Tables["Users"];
        datatableUsers.DefaultView.Sort = "Name";
        DataView dataviewUsers = datatableUsers.DefaultView;

        // Loop Through Rows and Add UsersGrid to FlowLayoutPael
        foreach (DataRowView datarowviewUsers in dataviewUsers)
        {
            var UsersGrid = new UsersGrid
            {
                Username = datarowviewUsers["Username"].ToString(),
                User = datarowviewUsers["Name"].ToString(),
                Admin = datarowviewUsers["Administrator"].ToString(),
            };
            flowlayoutpanelUsers.Controls.Add(UsersGrid);
            UsersGrid.MouseClick += new MouseEventHandler(user_click);
        }
    }

    private UsersGrid selectedUser;

    void user_click(object sender, EventArgs e)
    {
        if (selectedUser != null)
            selectedUser.BorderStyle = BorderStyle.None;
        selectedUser = (UsersGrid)sender;
        selectedUser.BorderStyle = BorderStyle.FixedSingle;
    }

My issue is that it only works when I click in a white space in the UserControl but not when the user clicks on the two labels or image. How do I make it work for all child objects too?

Also, how can I then use the selected UserControl to do other things like open a form which shows all the details for that selected user?

解决方案

I have a few suggestions for you. At the bottom of my response I included code that demonstrates my suggestions.

Suggestion 1: Fixing MouseClick in your UC
When you register the MouseClick event for a UserControl (UC) you're doing so for the UserControl itself, not for any controls that you place on the UserControl such as your Labels, etc. If you click one of these child controls the click won't be 'seen' by the underlying UC.

To fix this register the MouseClick event for all your child controls; you can even register the same MouseClick event handler you have for the UserControl itself.

Suggestion 2: Setting your UC's BorderStyle
I'd move your code for setting the UC's BorderStyle into the UC itself. Create public property IsSelected that's set to true when the UC is selected. In the property's setter update the UC's BorderStyle property depending on the value of the property.

Exposing an IsSelected property for your UC can be handy: you can query a group of these UCs to see which ones are selected rather than trying to track this status outside of the control like through a Form-level variable.

Edit in response to your comment:
Here's an example of how you might query the UCs in a FlowLayoutPanel to see if any are selected and if one is found how you might take some action. In this case the action is to call an EditUser method that takes as parameters values you get from properties in the selected UC:

var selectedUC = flowLayoutPanel.Controls.Cast<UserControl1>().FirstOrDefault(uc => uc.IsSelected);
if (selectedUC != null) {
    // Use the properties of the UC found to be selected as parameters is method EditUser.
    EditUser(selectedUC.Name, selectedUC.Username, selectedUC.Administrator);
}

Suggestion 3: Managing selection in a group of your UCs
If you want to unselect all UCs in a group except for the one that the user clicks (i.e. selects) you'll need to create an event in your UC that fires when a UC is clicked. The handler for this event explicitly sets IsSelected to false for all UCs in a set (such as in a container type control such as a Form, FlowLayoutPanel, etc.), the MouseClick handler in the UC that was clicked will then set the clicked UC's IsSelected to true.

It's worth considering creating another UserControl type that manages a group of your UCs. This new UserControl can encapsulate the code for the creation and state management of sets of your UC and would faciliate using your UCs in other projects as well as keeping the code of Forms hosting your UCs a bit cleaner.


I figured that rather than include a series of disjointed code snippets for each of my suggestions I'd include what I'm hoping is the minimum amount of code to allow you to reproduce what I'm talking about.

Create a new Visual Studio Winform project and use the following for class Form1:

public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();

        flowLayoutPanel = new FlowLayoutPanel {
            Dock = DockStyle.Fill,
        };
        this.Controls.Add(flowLayoutPanel);
        // Add several sample UCs.
        for (int i = 0; i < 10; i++) {
            var uc = new UserControl1();
            uc.WasClicked += UsersGrid_WasClicked;
            flowLayoutPanel.Controls.Add(uc);
        }
    }

    FlowLayoutPanel flowLayoutPanel;

    // Event handler for when MouseClick is raised in a UserControl.
    void UsersGrid_WasClicked(object sender, EventArgs e) {
        // Set IsSelected for all UCs in the FlowLayoutPanel to false. 
        foreach (Control c in flowLayoutPanel.Controls) {
            if (c is UserControl1) {
                ((UserControl1)c).IsSelected = false;
            }
        }
    }
}

Next add a UserControl to the project. Keep the name UserControl1 and add a couple Labels and a PictureBox. Use this code for class UserControl1:

public partial class UserControl1 : UserControl
{
    public UserControl1() {
        InitializeComponent();
        this.Load += UsersGrid_Load;
    }

    // Event fires when the MouseClick event fires for the UC or any of its child controls.
    public event EventHandler<EventArgs> WasClicked;

    private void UsersGrid_Load(object sender, EventArgs e) {
        // Register the MouseClick event with the UC's surface.
        this.MouseClick += Control_MouseClick;
        // Register MouseClick with all child controls.
        foreach (Control control in Controls) {
            control.MouseClick += Control_MouseClick;
        }
    }

    private void Control_MouseClick(object sender, MouseEventArgs e) {
        var wasClicked = WasClicked;
        if (wasClicked != null) {
            WasClicked(this, EventArgs.Empty);
        }
         // Select this UC on click.
         IsSelected = true;
    }

    private bool _isSelected;
    public bool IsSelected {
        get { return _isSelected; }
        set {
            _isSelected = value;
            this.BorderStyle = IsSelected ? BorderStyle.Fixed3D : BorderStyle.None;
        }
    }
}

这篇关于从FlowLayoutPanel中选择UserControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆