WPF How to access control from DataTemplate
First of all, I can't even find the relation between the Resource (ShowAsExpanded) and the usage inside the ContentPresenter. But for the moment, let's assume that the DynamicResource should point to ShowAsExpanded.
You can't and shouldn't access the combobox via code. You should bind the datacontext to the grid that uses the style. If you don't want to do that, you will have to find the content at runtime and search for the child combobox.
How do I access a control inside a XAML DataTemplate?
The problem you are experiencing is that the DataTemplate
is repeating and the content is being generated by the FlipView
. The Name
is not exposed because it would conflict with the previous sibling that was generated (or the next one that will be).
So, to get a named element in the DataTemplate
you have to first get the generated item, and then search inside that generated item for the element you want. Remember, the Logical Tree in XAML is how you access things by name. Generated items are not in the Logical Tree. Instead, they are in the Visual Tree (all controls are in the Visual Tree). That means it is in the Visual Tree you must search for the control you want to reference. The VisualTreeHelper
lets you do this.
Now, how to do it?
I wrote an article on this because it is such a recurring question: http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html but the meat of the solution is a recursive method that looks something like this:
public void TestFirstName()
{
foreach (var item in MyFlipView.Items)
{
var _Container = MyFlipView.ItemContainerGenerator
.ContainerFromItem(item);
var _Children = AllChildren(_Container);
var _FirstName = _Children
// only interested in TextBoxes
.OfType<TextBox>()
// only interested in FirstName
.First(x => x.Name.Equals("FirstName"));
// test & set color
_FirstName.Background =
(string.IsNullOrWhiteSpace(_FirstName.Text))
? new SolidColorBrush(Colors.Red)
: new SolidColorBrush(Colors.White);
}
}
public List<Control> AllChildren(DependencyObject parent)
{
var _List = new List<Control>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var _Child = VisualTreeHelper.GetChild(parent, i);
if (_Child is Control)
_List.Add(_Child as Control);
_List.AddRange(AllChildren(_Child));
}
return _List;
}
The key issue here is that a method like this gets all the children, and then in the resulting list of child controls you can search for the specific control you want. Make sense?
And now to answer your question!
Because you specifically want the currently selected item, you can simply update the code like this:
if (MyFlipView.SelectedItem == null)
return;
var _Container = MyFlipView.ItemContainerGenerator
.ContainerFromItem(MyFlipView.SelectedItem);
// then the same as above...
How do I access a control of a DataTemplate
Try this piece of code to reach to a control inside ContentPresenter:
public static FrameworkElement GetControlByName(DependencyObject parent, string name)
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i < count; ++i)
{
var child = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
if (child != null)
{
if (child.Name == name)
{
return child;
}
var descendantFromName = GetControlByName(child, name);
if (descendantFromName != null)
{
return descendantFromName;
}
}
}
return null;
}
How to find control from datatemplate of tabitem wpf
Building on @mm8 approach, the following solution will find the ListBox
by name instead of by type:
XAML
<TabControl x:Name="tabControl1" SelectionChanged="tabControl1_SelectionChanged">
<TabItem x:Name="tab1" Header="ABC">
<TabItem.ContentTemplate>
...
Code
private void tabControl1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() => TabItem_UpdateHandler()));
}
void TabItem_UpdateHandler()
{
ContentPresenter myContentPresenter = tabControl1.Template.FindName("PART_SelectedContentHost", tabControl1) as ContentPresenter;
if (myContentPresenter.ContentTemplate == tab1.ContentTemplate)
{
myContentPresenter.ApplyTemplate();
var lb1 = myContentPresenter.ContentTemplate.FindName("listBox", myContentPresenter) as ListBox;
}
}
how to access a control within Data Template from code behind?
You should be able to access your control using the FrameworkTemplate.FindName
method... first, get the ContentPresenter
from one of the ListBoxItem
s:
ContentPresenter contentPresenter = FindVisualChild<ContentPresenter>(yourListBoxItem);
Then get the DataTemplate
from the ContentPresenter
:
DataTemplate yourDataTemplate = contentPresenter.ContentTemplate;
Then get the MediaElement
from the DataTemplate
:
MediaElement yourMediaElement = yourDataTemplate.FindName("vidList", contentPresenter)
as MediaElement;
if (yourMediaElement != null)
{
// Do something with yourMediaElement here
}
Please see the FrameworkTemplate.FindName
Method page on MSDN for more information.
How to get value of XAML Control from DataTemplate
You can get the Button
's parent (i.e. StackPanel
), and then its parent's parent (i.e. Grid
), and then go down and find the TextBox
.
But... Don't do this. What if you changed the hierarchy, or the type of the Panel
?
Since you already know the type (i.e. Ausstattung
) of the DataContext
of your data template, you should create another property say TextValue
and have it two-way bound with the TextBox
. Then, you can either get its value from a CommandParameter
if you use Button
's Command
, or in code-behind -
private void ButtonBase_Click(object sender, RoutedEventArgs e)
{
var button = (ButtonBase)sender;
var dataContext = (Ausstattung)button.DataContext;
var value = dataContext.TextValue;
}
Your class needs to implement INotifyPropertyChanged
. After that, create a new property like this -
using System.ComponentModel;
using System.Runtime.CompilerServices;
using App1.Annotations;
namespace App1
{
public class Ausstattung : INotifyPropertyChanged
{
private string _textValue;
public string TextValue
{
get => _textValue;
set
{
_textValue = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In your xaml, do this -
<TextBox Text="{x:Bind TextValue, Mode=TwoWay}" Grid.Column="3" Foreground="White" FontSize="14" x:Name="txtAnzahl" PlaceholderText="{x:Bind Anzahl}" TextChanged="TextBox_OnTextChanged" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>
Related Topics
Webdriver How to Wait Until the Element Is Clickable in Webdriver C#
Automatically Rename a File If It Already Exists in Windows Way
How to Convert String to Integer in C#
Edit Raw Pixel Data of Writeablebitmap
Visual Studio 2010: How to Enforce Build Order of Projects in a Solution
How to Remove a Single Attribute (E.G. Readonly) from a File
How to Check If a String Is a Number
How to Set a Character at an Index in a String in C#
How Should You Diagnose the Error Sehexception - External Component Has Thrown an Exception
..The Underlying Connection Was Closed: an Unexpected Error Occurred on a Receive
How to Dynamically Switch Web Service Addresses in .Net Without a Recompile
Linq to Find Series of Consecutive Numbers
System.Drawing in Windows or ASP.NET Services
JSON.Net Custom Serialization with JSONconverter - How to Get the "Default" Behavior