retrieve usercontrol from itemscontrol item - wpf

i'm new to wpf and i am having a problem with items control. What i want to do is that i want to retrieve the user control that i've added in itemtemplate of items control. I tried using LoadContent() method of DataTemplate but it returns me the default template.
Here my code
ItemsControl parent = FindParent<ItemsControl>( this );
//this.isEditMode = true;
//this.editIngLayer.Visibility = Visibility.Visible;
foreach( var container in parent.Items )
{
DependencyObject contentPresenter=
parent.ItemContainerGenerator.ContainerFromItem( container ) as ContentPresenter;
//Something to retrieve the usercontrol
MyUserControl uC=contentPresenter.GetControl();
//
}
Thanks.

If you have your ItemsControl item with you then you can iterate its Visualtree to reach to your usercontrol using VisualTreeHelper
Recursive find child is explained in this post
How can I find WPF controls by name or type?

Related

Expand Root in TreeView when ItemSource changed

I have a ChildWindow in a Silverlight 4 App with a TreeView. The ItemSource is binded to an ObservableCollection of Items in a ViewModel. When the window opens the item are loaded from a webservice.
I have only one root node and I need it to be initially expanded. The TreeView even has the extension ExpandToDepth() which seems perfect but I don't know where I can call it. I didn't find an event that occurs after the items are updated from the ItemSource.
I tried using ItemContainerGenerator.ItemChanged and OnItemsChanged in TreeView but they are both executed before the tree view items are generated so the expand commands won't work.
How can I get this to work?
Try to register for your ObservableCollection's CollectionChange Event and do your actions there.
Derive from TreeView and create IsRootItemExpanded property and create same name property in ViewModel. In set accesser check if value true then call your method like this ExpandToDepth(1) When itemssource is need to update then set IsRootItemExpanded property true. You must to bind IsRootItemExpanded of TreeView to IsRootItemExpanded of ViewModel.
I solved my problem by overriding the PrepareContainerForItemOverride method in TreeView. I wondered why this is just called for the root node but it works.
public class ExpandedRootTreeView : TreeView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
TreeViewItem treeViewItem = element as TreeViewItem;
if (treeViewItem != null) treeViewItem.IsExpanded = true;
base.PrepareContainerForItemOverride(element, item);
}
}
Thanks to everybody who responded.

Accessing TextBoxes in WPF DataBound ListBox with foreach

I have a databound WPF ListBox with a custom itemtemplate -> datatemplate. Part of that template is also a ListBox.
On certain event I'd like to loop through all textboxes in the ListBox and retreive their values.
Is this possible?
You should be able to do this by using the ItemContainerGenerator and finding elements in the template:
foreach (var item in lb.Items)
{
var itemContainer = lb.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
// Name the TextBox in the template to find it here.
var textBox = itemContainer.ContentTemplate.FindName("?????", itemContainer) as TextBox;
var value = textBox.Text;
}
(If the TextBoxes you referred to are within the ListBox which is in the template you have to dig deeper by repeating the same method.)

WPF Accessing Items inside Listbox which has a UserControl as ItemTemplate

I have Window that has a ListBox
ListBox(MyListBox) has a DataTable for its DataContext
ListBox's ItemSource is : {Binding}
Listbox has a UserControl(MyUserControl) as DataTemplate
UserControl has RadioButtons and TextBoxes (At first They're filled with values from DataTable and then user can change them)
Window has one Submit Button
What I want to do is, when user clicks the submit button
For each ListBox Item, get the values form UserControl's TextBoxes and RadioButtons.
I was using that method for this job :
foreach(var element in MyListBox.Items)
{
var border = MyListBox.ItemContainerGenerator.ContainerFromItem(element)as FrameworkElement;
MyUserControl currentControl = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(myBorder,0) as Border,0)as ContentPresenter,0)as MyUserControl;
//And use currentControl
}
I realised nothing when using 3-5 items in Listbox. But when I used much more items, I saw that "var border" gets "null" after some elements looped in foreach function.
I found the reason here :
ListView.ItemContainerGenerator.ContainerFromItem(item) return null after 20 items
So what can I do now? I want to access all items and get their values sitting on user controls.
Thanks
You should use objects who implement INotifyPropertyChanged and bind an ObservableCollection of it to the ItemSource
And then you can get all the list of items.
Here some quick links from MSDN to get more informations
How to: Implement Property Change Notification
Binding Sources Overview
You should google for some tutorials about this.
Zied's post is a solution for this problem. But I did the following for my project:
I realised that there's no need to use UserControl as DataTemplate in my project. So I removed ListBox's DataTemplate.
I removed MyListBox.DataContext = myDataTable and used this:
foreach(DataRow dr in myDataTable.Rows)
{
MyUserControl muc = new MyUserControl(dr);
myListBox.Items.Add(muc);
}
I took DataRow in my UserControl's constructor and did what I want.
And at last I could access my UserControls in ListBox by using :
foreach(MyUserControl muc in
myListBox)
{
//do what you want
}
Easy huh? :)

How to assign value of the dataContext to ListBox control in silverlight?

Hi I have contentControl in my user control. I am applying style to this contentControl which consist of TextBlock and ListBox. I am binding text of the textBlock to CategoryName(from Tag of the control). I want to bind category's child items to listBox. I have set ContentControl's dataContext property to child items[]. Now how to bind these child items to listbox which is in resource.
In loaded event of the user control
Panel pnl = sender as Panel;
Category category = panel.Tag as Category;
Items[] items = GetChildItemsByCategoryId(category.CategoryID);
mainContent.DataContext = items;
If the control is in the visual tree of mainContent, simply set in code or XAML
ItemsSource={Binding}

How do I load user controls dynamically?

How can I load a user control[s] in a window dynamically (using code at runtime)?
I'd highly recommend having a look at Prism, since composite user interfaces is what it's for. However, since this would require you refactoring your entire application, I'll also answer your question directly.
If you want a single user control in a container, put a ContentControl in your XAML and then set the Content property. If you are using a view model, you could bind Content to a FrameworkElement property on the view model:
contentControlInstance.Content = new CustomUserControl();
If you want multiple controls in a list, use an ItemsControl and assign an ObservableCollection<> to the ItemsSource property. If you are using a view model, you could bind ItemsSource to an ObservableCollection property on the View Model.
Then you can just add/remove views from that ObservableCollection:
private ObservableCollection<FrameworkElement> views =
new ObservableCollection<FrameworkElement>();
private void Initialize()
{
itemsControl.ItemsSource = views;
}
private void AddView(FrameworkElement frameworkElement)
{
views.Add(frameworkElement);
}
For adding multiple controls you need container.
Suppose you have a StackPanel container "myStack"
<Window ..>
<StackPanel Name="MyStack" />
</Window>
You can create control dynamically and add it to container. See code below
void AddButtons()
{
Button B1=new Button(),B2=new Button(), B3=new Button();
B1.Content="Hello";
B2.Content="First";
B3.content="Application";
// Now you can set more properties like height, width, margin etc...
MyStack.Children.Add(B1);
MyStack.Children.Add(B2);
MyStack.Children.Add(B2);
}
Or use binding. Here's a really crude example showing how different WPF controls can be shown in a single WPF window using ContentControl and binding (which is what a toolkit like Prism or Caliburn Micro does).
XAML:
<UserControl x:Class="ViewA">
...
<UserControl/>
<UserControl x:Class="ViewB">
...
<UserControl/>
Code:
void ShowViewModelDialog (object viewModel)
{
var host = new MyViewHost();
FrameworkElement control = null;
string viewModelName = viewModel.GetType().Name;
switch (viewModelName )
{
case ("ViewModelA"):
control = new ViewA();
break;
case ("ViewModelB"):
control = new ViewB();
break;
default:
control = new TextBlock {Text = String.Format ("No view for {0}", viewModelName);
break;
}
if (control!=null) control.DataContext = viewModel;
host.DataContext = control;
host.Show(); // Host window will show either ViewA, ViewB, or TextBlock.
}

Resources