I am trying to create a nested DataGridView control where there will be two levels of nesting that are open at all times. It will look similar to the picture on this page: http://www.codeproject.com/Articles/12657/GridView-inline-Master-Detail-record-display. The difference will be that each subnesting will always be open and it is not necessary to have a way for the user to open/close each nesting. This control will only be used for displaying data, so there will be no need to modify the data directly from this control (even though the user will not modify the data directly it can still be changed).
If this can not be done with DataGridView, is there any other control that would allow for this.
If not does anyone know another way to do this. I can, but they would be tedious to implement. One way would be to add multiple DataGridView controls in sequence (2N DataGridControls for N categories). The other would add it all manually with static controls.
I don't know if this will give the answer, but it might make u some door.
//button to call function that looks for DatagridView control
private void button2_Click(object sender, EventArgs e)
{
scanDG(this);
}
private void scanDG(Control parent)
{
foreach (Control ctrl in parent.Controls)
{
if (ctrl.GetType().Name == "DataGridView")
{//If current Control is Datagridview then set Readonly to true
((DataGridView)ctrl).ReadOnly = true;
}
//If a control can contain control scan it and look for Datagridview control
if (ctrl.HasChildren) scanDG(ctrl);
}
}
Related
I am facing an issue while running through all the User Controls in my Windows form.
I am creating a Windows Form that has the following features:
The Main form has 3 User Controls embedded in it
The Main form also has a combo box. Selecting a particular value in the Combo box will bring the corresponding User Control to the front.
Each User Control has two Check boxes as well as two Combo boxes.
The User can summon each User Control through the Main Form's combo box and check the check boxes and/or modify the combo boxes inside each User Control
Once this is done, there is a button, which on being pressed, executes the following code. This code is supposed to check which check boxes have been checked from every User Control, and execute some functionality :
private void button1_Click(object sender, EventArgs e)
{
foreach (Control c in this.Controls)
{
if (c is UserControl)
{
foreach (Control ctl in c.Controls)
{
if (ctl is CheckBox && (ctl as CheckBox).Checked)
{
Indicator.Text = "It's in";
}
}
}
}
//Some other code after this
}
Here, I have included a Text Box called "Indicator" that shows whether the compiler has entered a particular "for" loop or "if" block. And I'm observing that the innermost "if" alone is not getting executed.
Could someone point out why exactly this is happening?
You need a recursive algorithm,
void ProcessControls(Control ctrlContainer)
{
foreach (Control ctrl in ctrlContainer.Controls)
{
if (ctrl is CheckBox && (ctrl as CheckBox).Checked)
{
Indicator.Text = "It's in";
}
if (ctrl.HasChildren)
ProcessControls(ctrl);
}
}
I do think you might be better off adding some functionality to your user control so it can describe the state of its own checkboxes rather than going digging inside it to find it and do logic. Generally in OO programming, when we encapsulate things within a class, we also provide general purpose accessors "visible to the outside" to describe the internal state of affairs, rather than letting external code interests go poking around inside class to find out what they want
At some point in time you've added these usercontrols to the form either directly in the designer, or programmatically. In the first case they will have their own name:
var u1 = usercontrol1.GetCheckboxStateArray();
var u2 = usercontrol2.GetCheckboxStateArray();
Etc
Or maybe you added them programmatically, in which case it would make sense to keep track of them in a list as you're adding them:
protected List<UserControl> _ucList = new List<UserControl>();
...
foreach(var result in somedatabasequery){
var uc = new UserControl(result.Whatever);
this.Controls.Add(uc);
_ucList.Add(uc);
}
Then this list can be iterated. Sure you could argue that "well .Controls is a collection too, so why add them to another list when they're already in an accessible collection" - for the reasons you're here; .Controls is a general purpose description of the hierarchy of all controls on a form, it contains stuff we don't want and is hard to iterate. This List is purely and simply all and only the stuff we're interested in
As an aside, the UI you have described is atypical. The more usual way of hiding and showing controls under the selection of something that holds a bit of text would be a TabControl. It might be easier to loop through too, if you will persist with this "search for UserControls in a collection of controls" method - tabcontrols have tabpages, tabpages would probably have a .Controls that just contains your UserControl. The tabpage intrinsically takes care of showing and hiding controls as pages are clicked on which could simplify your code
Thanks to everyone for the answers. As it happens, the issue was hiding in plain sight, right under my nose. In each of the User Controls, I had placed the Checkboxes and Combo Boxes inside a Group Box. It completely slipped my mind, so much so that I didn't even mention them in my question.
Thus, as #Caius had suggested in the comments, the code wasn't functioning because I had not addressed the Group Box Container holding these Controls. Once I removed the Group Boxes (used only for aesthetic purpose), the code started functioning properly.
I have a UserControl that is dynamically added to a FlowLayoutPanel. In that same UserControl I have a button to remove itself if the user wants it, obviously at runtime. To eliminate I mean not only to eliminate that tight button, but also the full UserControl that contains the button.
The code of when the UserControl are added dynamically at the moment is as follows:
private void agregaUC() {
UserControl1 UC = new UserControl1();
aux += 1;
UC.Tag = aux.ToString();
flowLayoutPanel2.Controls.Add(UC);
}
The code to eliminate this is on the side of the form, that is, where the UserControl are being added. The button event to remove the UserControl is thrown by code through the operator + =, then there I write the suggestions that you give me.
EDIT: Based on the sample of code you've added, I've modified the below code to work better with what you are looking for. You need to find out how to access the Tag of the control you're trying to remove.
Since you don't have a reference, then you should make sure that the .Tag property can be found, because then you can do something like
foreach (Control c in flowLayoutPanel2.Controls) {
if (c.Tag == "Aux") {
flowLayoutPanel2.Controls.Remove(c);
c.Dispose();
break;
}
}
EDIT
Reading through all the comments everywhere, it seems like this is what's happening. There is a UserControl, inside that user control is a Button (Delete) and the button's Click event is subscribed to by the window, and it's in this event handler that we're trying to remove the UserControl from flowLayoutPanel2
Based on these assumptions, your function should look like this:
void UserControl_Delete_Click(object sender, EventArgs e)
{
Button Delete = (Button)sender;
UserControl UC = (UserControl)Delete.Parent;
flowLayoutControl2.Controls.Remove(UC);
UC.Dispose();
}
This is assuming a lot about the internal structure of everything, as I don't have the code to confirm this will work. It will get you a long ways down the path, though, and should only need a little tweaking based on the actual structure of the UserControl.
You can try something like that.
this.Parent.Controls.Remove(this);
Control.Parent Property.
Remark: Setting the Parent property value to null removes the control from the Control.ControlCollection of its current parent control.
So
this.Parent = null;
Edit
The code is intended to be called from within the user control itself.
if I add control in Microsoft Blend 4 without set Name to this control and I want to set name to it and use it in c# how ?
example I added button using Blend in my layout but without give it a name
I want to give it a name using c# without x:Name="" in xaml
In your place I would give LogicalTreeHelper.GetChildren (this) a chance. It returns a collection of children to Window (this is a handle to Window) Reference MSDN
From there you can try to find your control.
But I think it is easier to try to rewrite the control (or look for another component) so you can have names on the children. That was your problem from the start.
Hope it helps
Gorgen
First, why in the world would you want to do that?
If you do not set a name you have no easy way of accessing the control. However you can get access to the control via relationships to other controls or events that pass a reference, for example the loaded event.
e.g.
private void Menu_Loaded(object sender, RoutedEventArgs e)
{
(sender as Menu).Name = "MainMenu";
}
Or if the control is the child of another control:
(ControlStack.Children[0] as Menu).Name = "MainMenu";
But i cannot think of anything useful that could be achieved by that...
You probably just want to get a reference to the object which you can easily store in a class member. In some cases you can also slice up your XAML using resources.
e.g.
<local:SomethingIWouldLikeToReference x:Key="SomethingIWouldLikeToReference"/>
<local:UserControl x:Name="userControl">
<Stuff>
<MoreStuff Content="{StaticResource SomethingIWouldLikeToReference}"/>
</Stuff>
</local:UserControl>
public MainWindow()
{
InitializeComponent();
MyReference = FindResource("SomethingIWouldLikeToReference") as SomethingIWouldLikeToReference;
}
Example if I have ListView Control and I want to use it to add items and remove items
Make private ListView and initialize it
ListView temp_control_List = new ListView()
then make loaded Eventhandler from Blend so it will be in VS then
private void ListView_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
temp_control_List = sender as ListView;
}
Now you can add and remove to and from the list view control from temp_control_List
I'm trying to create a self-contained Winforms control called DragDropListView. It derives from ListView.
I have code that allows the user to sort list items within the control by dragging and dropping the items in the new location. I achieved that by overriding OnDragDrop, OnDragOver, OnDragEnter, OnItemDrag.
The issue I have is with dragging from one listview to a completely different listview. The event fires on the other list view as expected, but the method doesn't take a "sender" argument, so there's no good way to tell where the items are being dragged from, and no way I can figure out to actually grab the items being dragged. The current code works with stuff like "this.SelectedItems," but I'd like it to be "sender.SelectedItems".
I guess the reason there is no sender argument is that the control isn't supposed to responsible for knowing that much about its environment, and the host Form should handle the interaction between two controls, but I'm trying to build self contained controls that have this functionality, so letting it bleed onto the form isn't going to work.
Ideas?
I think you can know the ListView from the Items by listViewItem.ListView property, Check it.
I didn't test the code:
private void listView1_DragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(typeof(ListView.ListViewItemCollection)))
{
e.Effect = DragDropEffects.None;
return;
}
var items = (ListView.ListViewItemCollection)e.Data.GetData(typeof(ListView.ListViewItemCollection));
if (items.Count > 0 && items[0].ListView != listView1)
{
e.Effect = DragDropEffects.None;
return;
}
}
Check DragEventArgs , this sample in CodeProject [VB.Net]
Good luck!
I have a dialog with loads of control in it. Each and evey control will be populated during the loading sequence and it might take a while for it to get completely filled. Mean while, I don't wanna allow the user to click on any of the controls. In other words, I wanna disable the control from receiving the events and I don't wanna disable the controls (as it might look odd).Also, I don't wanna subscribe and unsubscribe for the events regular intervals. Is there any way to stop the controls from listening to the events for a brief time ??
Sudarsan Srinivasan
The whole point of disabling controls is to communicate to the user that the control cannot be used at a particular time. This is a convention that users have learned and are used to, so I would advice to follow that. Not doing that may confuse the users.
The easiest way is to disable the container in which the controls are located in, rather than disabling each and every control. A better way (or at least the way that I prefer) is to have a method that will control the Visible and Enabled properties of controls based on which state the UI is in.
The easiest way is to move the control population out of the load event (if possible). Then in Load do something like:
private bool _LoadComplete;
void OnFormLoad(Object sender, EventArgs e)
{
_LoadComplete = true;
InitializeControls();
_LoadComplete = false;
}
void InitializeControls()
{
// Populate Controls
}
void OnSomeControlEvent()
{
if (_LoadComplete)
{
// Handle the event
}
}
Edit A Couple other Ideas:
Set the Application.Cursor = WaitCursor (typically will disallow clicking, but not a 100% guarantee)
Create a "Spinner" control to let the user know that the screen is busy. When loading bring it to the front so it sits on top and covers all other controls. Once you're done loading set it to visible = false and show your other controls
Unfortunately the only way i know of is to have a class variable (called something like _loading) and in each control handler do something like:
If (! _loading )
{
...
}
And in your loading code set _loading = true; once you have finished loading.
If you just want to disable user input, then you can set the form's Enabled property to false.
This has the effect of blocking user input to any of the form's controls, without changing the appearance of the controls; it's the technique used internally by the ShowDialog method.