How to loop through a set of controls on a WPF Window
Hi, basically i need to loop through controls on WPF window and for perform actions with the control and gather data from it based on its type.
I have done this before in windows forms, in WPF however i am having some problems.
I'm afriad the actual code is at work and i won't be in till tomorrow, at which point i will update this thread with it.
From my memory creating a loop such as this in Vb.net works fine.
1 Code:
For each c as control in Me.Controls
...
Next
However as WPF is different i tried using Me.content to no avail and other variations that threw an error.
Ideas?
Cheers :)
Re: How to loop through a set of controls on a WPF Window
Re: How to loop through a set of controls on a WPF Window
Yeah tried that first off, before i posted here, no real help......
Re: How to loop through a set of controls on a WPF Window
Why is it no real help? The first link I looked at to had an example of how to do it...
http://social.msdn.microsoft.com/For...5-9168cb4bb8dd
Re: How to loop through a set of controls on a WPF Window
instead of me.controls you would reference whatever the container they are in and its children. so if your using a grid,stackpanel,wrappanel or whatever your using it would just be mygrid.children. i usually use an index number when i loop, but thats prob wrong. but i do this
Code:
For i as int32 = 0 to mygrid.children.count -1
If mygrid.children.item(i).gettype.fullname = gettype(Textblock).fullname then
Dim ctrl as Textblock = ctype(mygrid.children.item(i),Textblock)
'now you have this control. change textblock to whatever type you are looking for.
end if
next i
Re: How to loop through a set of controls on a WPF Window
Thanks for the help everyone, I tried everything you suggested chris. I was able to count the controls. However, i was unable to directly access the object of the control, I could only return the control type. I.E textbox, stackpannel etc. Other values such as Text, tags etc where not accessable and for my desired requirements, need to be.
I will try what you suggested saber; i tried a simular method without success, but yours is a bit different so may hopefully work.
To go into a bit more detail about the scenario....
my program creates controls based on data from an sql database. The way it does this is create a stackpannel, inside this stack pannel is a "title" textbox field and a "content" textbox field. There may be many of these stackpannels ( 10+) . Each stackpannel and control inside it will also contain the ID from the database in its .tag, this is the identifyer used for the resubmission of data to the database.
So in essence create a loop such as this.
Code:
For each control in the content window
If the control is a stackpanel then
For each textbox in that stackpanel
connect to sql based on the textbox.tag and update the record with the textbox.text data
next
end if
next
I will post back with any further developments :) , cheers everyone.
---------
EDIT
---------
I have For each loop version working, thanks for all the help , i will post it up later, so anyone else having this problem can see the solution.
Re: How to loop through a set of controls on a WPF Window
CJay, did you every solve this? I have a similar problem and I can't figure it out. I can use the code below to get to a GroupBox, but I cannot access the controls within the group box. I need to be able to read the tag on a label within the group box. Any help?
Code:
Private Sub SetFunLabels(ByVal TheTag As String)
For i As Int32 = 0 To Grid1.Children.Count - 1
If Grid1.Children.Item(i).GetType = GetType(GroupBox) Then
Dim ctrl As GroupBox = CType(Grid1.Children.Item(i), GroupBox)
' I can get the group box, but i can't get the grid within the group box nor can I get the labels and textboxes within the grid
End If
Next i
Re: How to loop through a set of controls on a WPF Window
you just need to loop through the container in the groupbox. i would assume you have a grid or a stackpanel or something like that in the groupbox, right? then in that container is where you have the rest of your controls. so you would need to do something like this.
Code:
For i As Int32 = 0 To Grid1.Children.Count - 1
If Grid1.Children.Item(i).GetType = GetType(GroupBox) Then
Dim ctrl As GroupBox = CType(Grid1.Children.Item(i), GroupBox)
If ctrl.Name = "myGroupBoxName" Then 'you might want to add this to make sure you are looping the correct groupbox in case you have more than 1
Dim grCtrl as Grid = CType(ctrl.content,Grid)
For x as Int32 = 0 To grCtrl.Children.Count - 1
'use the GetType function like we did above to find whatever control you want here
Next x
End If
End If
Next i
Re: How to loop through a set of controls on a WPF Window
Now it makes sense. Thanks you very much!
Re: How to loop through a set of controls on a WPF Window
The previously suggested way of doing this is a very non-WPF way of doing things. You shouldn't be pulling values from the UI. In this instance, what we have is a collection of fields that we want to display on the screen, so first of all let's define what we mean by a field (sorry, source code supplied in C#...):
Code:
public class DataField : INotifyPropertyChanged
{
private readonly string m_databaseId;
private readonly string m_title;
private string m_value;
public DataField(string databaseId, string title, string value)
{
m_databaseId = databaseId;
m_title = title;
m_value = value;
}
public string DatabaseId
{
get { return m_databaseId; }
}
public string Title
{
get { return m_title; }
}
public string Value
{
get { return m_value; }
set
{
if (m_value != value)
{
m_value = value;
OnPropertyChanged("Value");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var propertyChangedHandler = PropertyChanged;
if (propertyChangedHandler != null)
{
propertyChangedHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Okay, having got that, let's have a collection of those as our DataContext for a window (this is just a quick fudge to get a demo working. this would obviously come from the database in the real app, and be passed in to the form):
Code:
public Window1 ()
{
// Begin new stuff
ObservableCollection<DataField> fields = new ObservableCollection<DataField>();
fields.Add(new DataField("id1", "Field 1", "Value 1"));
fields.Add(new DataField("id2", "Field 2", "Value 2"));
fields.Add(new DataField("id3", "Field 3", "Value 3"));
fields.Add(new DataField("id4", "Field 4", "Value 4"));
this.DataContext = fields;
// End new stuff
InitializeComponent();
}
Right, so now we have a collection of fields as the DataContext for our Window. We want to first of all have some way of displaying a field, so let's create a DataTemplate for that:
Code:
<DataTemplate DataType="{x:Type WpfSandbox:DataField}">
<StackPanel>
<TextBlock Text="{Binding Title}" />
<TextBox Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
(Note that we're not setting the database id as the tag on the controls?)
Then we need have the whole set of fields showing in the window. Remeber that our collection of fields is the DataContext of the window:
Code:
<Window x:Class="WpfSandbox.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfSandbox="clr-namespace:WpfSandbox"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type WpfSandbox:DataField}">
<StackPanel>
<TextBlock Text="{Binding Title}" />
<TextBox Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding}" />
</Window>
When the values in the textboxes are altered, the changes will propagate back to the underlying DataField objects thanks to binding. Then the final part of the problem is to get at the DataFields at the end. Let's throw a button on the form to kick it off. Replace the ItemsControl with this:
Code:
<StackPanel>
<ItemsControl ItemsSource="{Binding}" />
<Button Click="Button_Click">Save</Button>
</StackPanel>
and then an event handle for the button click:
Code:
private void Button_Click (object sender, RoutedEventArgs e)
{
ObservableCollection<DataField> fields = (ObservableCollection<DataField>) this.DataContext;
foreach (DataField field in fields)
{
MessageBox.Show(string.Format("Field {0} (Title = {1}) Value: {2}", field.DatabaseId, field.Title, field.Value));
}
}
Re: How to loop through a set of controls on a WPF Window
Thanks for the extensive reply. Since I write VB for personal use and am using the project to learn WPF I want to avoid being "un-WPF". I'll check out Data Binding and try to translate your C# code. Thanks again.
Re: How to loop through a set of controls on a WPF Window
rcam,
Did you ever figure it out? I'm porting code into WPF that was done in VB and .net 2.0, and am stuck trying to do this. I have a bunch of text boxes on the screen, and while I could just do a "chkbox1.ischecked = false" type statement, I do not want to have to write like 200 lines of code each time i need to turn all boxes on or off.
I'm going to try some of the tips here, would like to know if there was an easy way for you to figure it out, as I really do not understand this whole "walking the visual tree" speak some other sites are mentioning.
Re: How to loop through a set of controls on a WPF Window
Due to the way WPF deals with UI, if you want to directly muck about with controls from your code then you have to walk the visual tree.
Much better to use WPF in the way it was intended. Your "application logic" alters some objects properties, and the UI is databound to those objects, causing it to react.
Re: How to loop through a set of controls on a WPF Window
I just had to solve this myself. I needed to clear the contents of all textboxes when moving from one item to another in a treeview.
Here is what I did:
foreach (UIElement element in grdContent.Children)
{
if (element.GetType).FullName== "System.Windows.Controls.TextBox")
{
TextBox txtClear = (TextBox)element;
txtClear.Text = "";
}
}
This is C# but I am sure you get the idea
Re: How to loop through a set of controls on a WPF Window
:check:
Thanks for the reply. I solved the problem by binding the controls to an observable listof (objects). and set the binding as two way. The list and controls update whenever the object element is changed. I still kind of feel like a glorified typist with WPF since I get the answers out of books or the web, without truly understanding why it works. However its getting clearer.