TextBox AutoCompleteStringCollection Suggest - c#

I have created a form in C# with a CustomSource for a textbox:
public partial class FormLookup : Form
{
AutoCompleteStringCollection source = new AutoCompleteStringCollection();
public FormLookup()
{
InitializeComponent();
source.Add("Test");
source.Add("TestItem");
source.Add("TestValue");
this.textBox1.AutoCompleteCustomSource = source;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
The result looks like this:
The purpose of what I am looking for is to select multiple values from the auto suggestion list. When the user selected the first value, a seperator like ';' should trigger the auto suggestion again.
It should look like this:
Maybe some code/idea in the _TextChanged method?
Is it possible in C# to highlight the selected value like in pic2?
Your ideas are welcome!

You need to create your custom control for this requirement.
I have created similar one. posting logic and code - hope it may help you in getting basic Idea.
You need to create two user controls.
Custom Control (container for second user control + text box which you show us in question)
Tag control (will contain label to show Text of tag and link label 'x' to remove it)
Together it will create a visualization of single unit custom control. where you can type (with you drop down suggestion) and once you press ',' , it will create a tag and store it within.
It will look like below,
Here is code for that.
Custom Control will have following cnntrols by default
private System.Windows.Forms.FlowLayoutPanel flayoutCustomControlContainer;
public System.Windows.Forms.TextBox textBox1; //Marking this public so it can be directly accessed by external code.
here flayoutCustomControlContainer is containing textBox1 by default.
textBox1 will have Key Up event, which will be like below.
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Oemcomma) //we will perform this on every ',' press
{
flayoutCustomControlContainer.Controls.Remove(textBox1);
TagControl tag = new TagControl(); //creating new Tag control
tag.lblTagName.Text = textBox1.Text.TrimEnd(",".ToCharArray());
tag.Remvoed += tag_Remvoed; //subscribing "Removed" event of Tag
tag.Width = tag.lblTagName.Width + 50;
tag.Height = tag.lblTagName.Height + 5;
flayoutCustomControlContainer.Controls.Add(tag);
textBox1.Text = "";
flayoutCustomControlContainer.Controls.Add(textBox1);
textBox1.Focus();
}
}
void tag_Remvoed(object sender, EventArgs e)
{
this.flayoutCustomControlContainer.Controls.Remove((Control)sender);
textBox1.Focus();
}
Constructor of Custom Control, as you shown in question,
public CustomControl()
{
InitializeComponent();
source.Add("Test");
source.Add("TestItem");
source.Add("TestValue");
this.textBox1.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
this.textBox1.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.CustomSource;
this.textBox1.AutoCompleteCustomSource = source;
}
Now, Tag Control.
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
public System.Windows.Forms.Label lblTagName;
private System.Windows.Forms.LinkLabel llblRemove;
link label, llblRemove will have link lable click event which will raise an event, which Custom control is listing.
private void llblRemove_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
if (Remvoed != null)
Remvoed(this, EventArgs.Empty);
}
Now, use this Custom Control anywhere you want to use.
I have uploaded working example project on GitHub.
Find a Link

You need create your own component.
The structure can be be:
Panel (the main container with white background and border)
|-> FlowLayoutPanel (the container for already added tags); Dock = Left
| |-> TagControl (you custom control for tag label)
| |-> ... (more tags if required)
|-> TextBox (the one with autocompletion with no borders); Dock = Fill;
You can encapsulate to your own Control/UserControl and use that event from Toolbox in designer.

Related

Accessing other buttons from one button's "click" method

How can I access other buttons from click method of one button? I'm working in Milestone SDK (c#, visual studio).
I've tried to use "this.", but it obviously doesn't work... (I'm novice in c#)...
In example below I can change "CONTENT" for bbt button object (bbt.Content = "TEST";):
private void bbt_Click(object sender, RoutedEventArgs e)
{
var bbt = sender as Button;
bbt.Content = "TEST";
}
but how can I change content for other buttons, defined in my code? For example, another button name is "action1"?
Maybe there is a way to declare something like that:
var bbt = sender as Button;
but for all other buttons so I can access them like I'm accessing "bbt"?
Would like to have a code that will allow mi to do:
action1.Content = "TEST";
where action1 is another button.
It looks like I need to add some prefix before referring to "action1", because otherwise it's not visible and generates:
CS0103 The name 'action1' does not exist in the current context
Looks like you are trying to change the button label.
If the button already exist just use:
private void bbt_Click(object sender, RoutedEventArgs e)
{
bbt.Text= "TEST";
}
If you have a container like a flowLayoutPanel,panels where the child is buttons you can use the forloop to get all the buttons and change it contents
//if without a container you must Name your buttons to button1,button2,button3
int i=0;
while(true){
i++;
Button button = new Button();
button.Name = "button"+i.toString();//output button1 to n
WindowsFormName.Controls.Add(button);
}
private void bbt_Click(object sender, RoutedEventArgs e)
{
//loop all controls
int y=0;
foreach(Control control in WindowsFormName.Controls){
y++;
string name = "Button"+y.toString();
//check if names are button1 or buttonN
if(control.Name.Equals(name){
control.Content = "TEST";
}
}
}
If the button was at the same hierarchy as the button being clicked you should be able to access it normally (e.g. action1.Text = "hello world";). I believe your problem may be that the button is on a child control.
If that is the case you have to write some type of recursive code to find the desired button (see the answer to this post to search for a control recursively Get control by name, including children)
Then call it:
var actionButton = this.FindControlRecursively<Button> ("action1");

c# xaml selecting controls using Name

I have the following dispatch routine in VS2013 C#:
private void B_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
string src = btn.Name.ToString();
string foo = "G" + src.Substring(1);
G0.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
It currently changes the visibility of G0. I want to change the code so that if Button B123 is pressed, then G123.Visibility is changed.
Thanks,
Dan
Note: This is a generic eventhandler for the buttons. There are 100's of buttons so an individual handler for each button is not practical. It could also be the handler from a dropdown or text box. G123 is a random control on the XAML page. The point is, given a string that contains the Name, how do I find the associated control so that I can modify its properties?
I'm not sure that I correctly understand your question, so I may be guessing that if button buttons B123 and G123 are related to each other by the number 123. In general, I suppose you want to change the visibility of button GX if button BX is changed.
In order to find all controls in the Window, have a look at the solution provided by Bryce Kahle, see Find all controls in WPF Window by type. In your buttenclick handle, do something like
private void B_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
string src = btn.Name.ToString();
string identifier= src.Substring(1);
foreach (var btn in FindVisualChildren<Button>(this).Where(b => b.Name.EndsWith(identifier)))
{
if(btn.Name.StartsWith("G"))
btn.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
Hope that helps.
In the comments, user Clemens gave the answer. (Since he didn't give it as an answer, I can't vote it up.)
Using FindName, I was able to get to the properties of the desired control:
private void B_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
string src = btn.Name.ToString();
string foo = "G" + src.Substring(1);
Windows.UI.Xaml.Shapes.Rectangle rect = (Windows.UI.Xaml.Shapes.Rectangle)this.FindName(foo);
rect.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
This has the flexibility so that I can change the fill, contents, text, foreground, style, etc. for a specified control. More control than if I had simply used XAML binding.
Thanks Clemens,
Dan

Check which submenu item was clicked in context menu strip

There is a ContextMenuStrip in a grid control.
I have named it as GridContextMenu.
The GridContextMenu is populated with 4 - 5 items using the following code :
gridcontextMenu.Items.Add(new ToolStripMenuItem
{
Name = Plants,
Text = Plants,
Tag = Plants,
Width = 100,
Image = <image source is put here>
});
gridcontextMenu.Items.Add(new ToolStripMenuItem
{
Name = Animals,
Text = Animals,
Tag = Animals,
Width = 100,
Image = <image source is put here>
});
For the animal menu in tool strip, i added submenu in the following way
(gridcontextMenu.Items[1] as ToolStripMenuItem).DropDownItems.Add("Tiger", image_source, new EventHandler(SubmenuItem_Click));
(gridcontextMenu.Items[1] as ToolStripMenuItem).DropDownItems.Add("Lion", image_source, new EventHandler(SubmenuItem_Click));
(gridcontextMenu.Items[1] as ToolStripMenuItem).DropDownItems.Add("Elephant", image_source, new EventHandler(SubmenuItem_Click));
In the SubmenuItem_Click event handler i need to know which animal submenu was clicked.
How to achieve this ?
currently i have the code for event handler in the following way :
private void SubmenuItem_Click(object sender, EventArgs e)
{
}
How to check condition in this event that which animal submenu was selected ?
Kindly share the answer.
You can do something like this:
private void SubmenuItem_Click(object sender, EventArgs e)
{
var clickedMenuItem = sender as MenuItem;
var menuText = clickedMenuItem.Text;
switch(menuText) {
case "Tiger":
break;
case "Lion":
break;
. ...
}
}
As I found that none of the other answers worked here, I went digging and found the proper solution. This may have been applicable only in .NET Framework 4+ but here is what I found to work.
Essentially, the ItemClicked event in the ContextMenuStrip control passes itself as the sender and a ToolStripItemClickedEventArgs object when the event is raised. As you can't obtain the clicked item from the ContextMenuStrip itself, the only way to obtain this information is to interrogate the ToolStripItemClickedEventArgs object and the clicked item resides in there as a ToolStripItem object. This can then be used to extract the name of the option to use in an if/switch statement as appropriate. See below:
To configure the EventHandler:
...
contextMenuStrip1.ItemClicked += OnContextMenuItem_Clicked;
...
To handle the event and retrieve the text of the clicked item:
private void OnContextMenuItem_Clicked(object sender, ToolStripMenuItemClickedEventArgs e)
{
ToolStripItem clickedItem = e.ClickedItem;
string itemName = clickedItem.Text;
...
}
Hopefully this helps someone looking for this answer in future :)
You can use Tag for this purpose in case when your should localize your application.
Moreover Tag is an object so you can put any tapy of data there. For example Enum type.
private void SubmenuItem_Click(object sender, EventArgs e)
{
var clickedMenuItem = sender as MenuItem;
EnumType item = (EnumType)clickedMenuItem.Tag;
switch(item) {
case TigeItem:
break;
case LionItem:
break;
...
}
}
This is a way to retrieve the ToolStripMenuItem's index if you have created the ContextMenuStrip Dynamically. It is really helpful with getting Enum values. My Context menu is dynamically created and filled with the Enum Names. I hope it helps someone. Sorry for the formatting still new to posting.
`private void DynamiallyCreatedContextMenu_Click(object sender, EventArgs e)
{
ToolStripMenuItem item = sender as ToolStripMenuItem;
var parent = (item.Owner as ContextMenuStrip);
for (int i = 0; i < parent.Items.Count; i++)
{
if (item == parent.Items[i])
{
index = i;
break;
}
}
}`
private void SubmenuItem_Click(object sender, EventArgs e)
{
string clickedItemName=e.ClickedItem.Text;
}

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
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;
}
}
}
I know this is old, but I landed here looking for some pointers on how to do UC selection in a Container.
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.
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
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.
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.
UIElement.GotFocus Event
UPDATE
This question may be appropriate: Click event for .Net (Windows Forms) user control

Access controls from a Usercontrol that is programmatically added more than once?

Well I've search a lot, and can't find help anywhere.
I have a form with tabs. When I click a button, a new tab is added, and a usercontrol is added to the new tab.
I cannot figure out how to access the controls on the second + tabs. I can access the user controls just fine from the first tab.. just not the others.
Here is the code I had so far.
private void button1_Click(object sender, EventArgs e)
{
string title = "tabPage " + (tabControl1.TabCount + 1).ToString();
TabPage newPage = new TabPage(title);
tabControl1.TabPages.Add(newPage);
UserControl1 newTabControl = new UserControl1();
newPage.Controls.Add(newTabControl);
}
private void button2_Click(object sender, EventArgs e)
{
label1.Text = userControl1.textBox1.Text;
}
So when I click button one, say 2 or 3 times, and how do I get the text from the textBox in the userControl from that tab?
...maybe I'm going about it all wrong?
You need to extend the TabPage and have properties that contain the child objects, for example:
public class ExtendedTabPage : TabPage
{
public UserControl1 UserControl { get; private set; }
public ExtendedTabPage(UserControl1 userControl)
{
UserControl = userControl;
this.Controls.Add(userControl);
}
}
Then you can access it via .UserControl as long as you still have a reference to it.. like so:
ExtendedTabPage newTab = new ExtendedTabPage(new UserControl1());
tabControl1.TabPages.Add(newTab);
newTab.UserControl.textBox1.Text = "New Tab User Control TextBox";
You will also have to go into the UserControl designer file and change the textbox declaration from private to public.

Categories

Resources