简体   繁体   English

从FlowLayoutPanel中选择UserControl

[英]Select UserControl from FlowLayoutPanel

I have set up UserControls in a FlowPanelLayout with the help in this question: For Each DataTable Add UserControl to FlowLayoutPanel 我在FlowPanelLayout中设置了UserControls,并在此问题中提供了帮助: For Each DataTable将UserControl添加到FlowLayoutPanel

I am now trying to implement a click event which allows me to put a border around the UserControl that has been selected. 我现在正在尝试实现一个click事件,它允许我在已选择的UserControl周围放置一个边框。 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. 我的问题是它只有在我点击UserControl中的空白区域时才有效,但是当用户点击两个标签或图像时却无效。 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? 另外,如何使用选定的UserControl执行其他操作,例如打开一个显示所选用户的所有详细信息的表单?

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

To fix this register the MouseClick event for all your child controls; 要修复此寄存器,请为所有子控件注册MouseClick事件; you can even register the same MouseClick event handler you have for the UserControl itself. 您甚至可以为UserControl本身注册相同的MouseClick事件处理程序。

Suggestion 2: Setting your UC's BorderStyle 建议2:设置UC的BorderStyle
I'd move your code for setting the UC's BorderStyle into the UC itself. 我将你的代码设置为UC的BorderStyle进入UC本身。 Create public property IsSelected that's set to true when the UC is selected. 创建公共属性IsSelected在选择UC时设置为true。 In the property's setter update the UC's BorderStyle property depending on the value of the property. 在属性的setter中,根据属性的值更新UC的BorderStyle属性。

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

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. 下面是一个示例,说明如何在FlowLayoutPanel中查询UC以查看是否有任何选定内容以及是否找到了如何执行某些操作。 In this case the action is to call an EditUser method that takes as parameters values you get from properties in the selected 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);
}

Suggestion 3: Managing selection in a group of your UCs 建议3:管理一组UC中的选择
If you want to unselect all UCs in a group except for the one that the user clicks (ie selects) you'll need to create an event in your UC that fires when a UC is clicked. 如果要取消选择组中除了用户单击(即选择)之外的所有UC,您需要在UC中创建一个在单击UC时触发的事件。 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. 此事件的处理程序为集合中的所有UC显式设置IsSelected为false(例如在容器类型控件(如Form,FlowLayoutPanel等)中),单击UC中的MouseClick处理程序将设置单击的UC的IsSelected真。

It's worth considering creating another UserControl type that manages a group of your UCs. 值得考虑创建另一个管理一组UC的UserControl类型。 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. 这个新的UserControl可以封装代码,用于创建和管理您的UC集合,并可以在其他项目中使用您的UC,以及保持托管您的UC的表单代码更清洁。


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 : 创建一个新的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;
            }
        }
    }
}

Next add a UserControl to the project. 接下来,将UserControl添加到项目中。 Keep the name UserControl1 and add a couple Labels and a PictureBox. 保持名称UserControl1并添加几个标签和PictureBox。 Use this code for class UserControl1 : 将此代码用于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 know this is old, but I landed here looking for some pointers on how to do UC selection in a Container. 我知道这是旧的,但我在这里找到了一些关于如何在Container中进行UC选择的指针。 Jay's answer works well. 杰伊的答案很有效。

Just one update: The UsersGrid_Load method will only engage the top level controls, children of containers will not participate in the WasClicked event. 只有一个更新: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);
}

Add recursive method RegisterMouseEvents to the UserControl 将递归方法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);
        }
    }

You could possibly try subscribing to the GotFocus event on the UserControl. 您可以尝试在UserControl上订阅GotFocus事件。

Caveat: 警告:

Because this event uses bubbling routing, the element that receives focus might be a child element instead of the element where the event handler is actually attached. 由于此事件使用冒泡路由,因此接收焦点的元素可能是子元素,而不是实际附加事件处理程序的元素。 Check the Source in the event data to determine the actual element that gained focus. 检查事件数据中的Source以确定获得焦点的实际元素。

UIElement.GotFocus Event UIElement.GotFocus事件

UPDATE UPDATE

This question may be appropriate: Click event for .Net (Windows Forms) user control 这个问题可能是合适的: 点击.Net(Windows窗体)用户控件的事件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM