从FlowLayoutPanel中选择UserControl

时间:2012-09-26 18:40:26

标签: c# select user-controls flowlayoutpanel

我已经在FlowPanelLayout中设置了UserControls,并提供了以下问题的帮助: For Each DataTable Add UserControl to FlowLayoutPanel

我现在正在尝试实现一个click事件,它允许我在已选择的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执行其他操作,例如打开一个显示所选用户的所有详细信息的表单?

3 个答案:

答案 0 :(得分:6)

我有一些建议给你。在我的回复的底部,我包含了演示我的建议的代码。

建议1:修复UC中的MouseClick
当您为UserControl(UC)注册MouseClick事件时,您正在为UserControl本身注册,而不是您放置在UserControl上的任何控件,例如您的标签等。如果您单击其中一个子控件,则单击赢了不会被潜在的UC'看到'。

要修复此寄存器,请为所有子控件修复MouseClick事件;您甚至可以为UserControl本身注册相同的MouseClick事件处理程序。

建议2:设置UC的BorderStyle
我会移动你的代码,将UC的BorderStyle设置为UC本身。创建选择UC时设置为true的公共属性IsSelected。在酒店的setter中更新UC的BorderStyle属性,具体取决于酒店的价值。

为您的UC公开IsSelected属性非常方便:您可以查询这些UC中的一组以查看选择了哪些,而不是像通过表单级变量一样尝试在控件之外跟踪此状态

编辑以回复您的评论:
下面是一个示例,说明如何在FlowLayoutPanel中查询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显式设置IsSelected为false(例如在容器类型控件中,如Form,FlowLayoutPanel等),然后单击UC中的MouseClick处理程序将将点击的UC的IsSelected设置为true。

值得考虑创建管理一组UC的另一个 UserControl类型。这个新的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并添加几个标签和一个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;
        }
    }
}

答案 1 :(得分:1)

我知道这已经过时了,但我在这里寻找关于如何在Container中进行UC选择的一些指示。 杰伊的答案很有效。

只需一次更新:UsersGrid_Load方法只会使用顶级控件,容器的子级不会参与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.
    RegisterMouseEvents(Controls);
}

将递归方法RegisterMouseEvents添加到UserControl

    private void RegisterMouseEvents(ControlCollection controls)
    {
        foreach (Control control in controls)
        {
            // Subscribe the control to the 
            control.Click += Control_MouseClick;
            if (control.HasChildren) RegisterMouseEvents(control.Controls);
        }
    }

答案 2 :(得分:0)

您可以尝试订阅UserControl上的GotFocus事件。

警告:

  

由于此事件使用冒泡路由,因此接收焦点的元素可能是子元素,而不是实际附加事件处理程序的元素。检查事件数据中的Source,以确定获得焦点的实际元素。

UIElement.GotFocus Event

<强>更新

这个问题可能合适:Click event for .Net (Windows Forms) user control