I see DataGrid databinding sytax as below:
ItemsSource="{Binding Path=ListDataColumns, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}"
The more complete code is:
<DataGrid KeyboardNavigation.ControlTabNavigation="Local" KeyboardNavigation.IsTabStop="False" DataContext="{Binding}"
ItemsSource="{Binding Path=ListDataColumns, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False" x:Name="DataGridColumnConfig" VerticalAlignment="Top" AllowDrop="True"
IsSynchronizedWithCurrentItem="True" CanUserSortColumns="False" CanUserDeleteRows="False"
CanUserAddRows="False" GridLinesVisibility="All" SelectedItem="{Binding Path=SelectedItem}" SelectedIndex="{Binding Path=SelectedItemIndex}">
I think the code is binding to a property called "ListDataColumns".
How can I determine from the ItemSource that which object is being bound to?
To answer your question completely, we would need more information from you. However, with what you have provided (and using a simplified XAML example), we can tell you the following:
<DataGrid DataContext="{Binding}" ItemsSource="{Binding Path=ListDataColumns,
Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True,
UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectedItem}"
SelectedIndex="{Binding Path=SelectedItemIndex}" ... />
The DataContext is set to {Binding} which is the same as {Binding Path=.} and means that we are binding to the current Binding.Source... in other words, one of the parents of this control should have an instance of an object set as its DataContext and this control will share that same object and have access to the same properties.
The ItemsSource property is set to {Binding Path=ListDataColumns ...} which is the same as {Binding ListDataColumns ...} and means that it will look in whatever object is set as the DataContext (of the parent control) for a property named ListDataColumns.
The SelectedItem property is set to {Binding Path=SelectedItem} which is the same as {Binding SelectedItem} and means that it will look in whatever object is set as the DataContext (of the parent control) for a property named SelectedItem.
The SelectedIndex property is set to {Binding Path=SelectedItemIndex} which is the same as {Binding SelectedItemIndex} and means that it will look in whatever object is set as the DataContext (of the parent control) for a property named SelectedItem.
That is about all that can be taken from your XAML example (ignoring the other Binding properties). However, for users learning XAML and WPF, here are some very useful links on MSDN for help with property path syntax:
Binding.Path Property
PropertyPath XAML Syntax
Property Path Syntax
Related
I was set the mode FindAncestor and Ancestor Type as X:Type as DataGrid and set the ClickCommand to the path.Now,my question is why to set the FindAncestor and AncestorType what is the actual behavior in the button command.
Thanks
FindAncestor and `AncestorType`
are used especially when for some reason , you can't access the datacontext of the window with your control.
Take this as example:
<DataTemplate DataType="DataGridColumnHeader" >
<ComboBox ItemContainerStyle="{StaticResource SingleSelectionComboBoxItem}" DisplayMemberPath="Oggetto" Width="100" Height="20" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.Selezione, UpdateSourceTrigger=LostFocus}" SelectionChanged="SingleSelectionComboBox_SelectionChanged"/>
</DataTemplate>
DataGridHeader doesn't inherit the datacontext of the datagrid, so i had to use that sintaxt to take the datacontext from the ancestor and set the itemsource
I have a ListBox which DataTemplate is TextBox that can be edited. Where should I set Binding TwoWay? In ItemSource or In TextBox binding? Maybe in both? And how it works inside? Is it inherited? So if I set Binding in ItemSource - is it inherited in TextBox?
<ListBox HorizontalAlignment="Left" ItemsSource="{Binding Commands, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Two way binding should be setup op your item you need to display, in this case the Textbox. Here you need to have coupling back to your datacontext. You might want to consider setting the UpdateSourceTrigger property to PropertChanged.
This way you will always have entered value of your text, even without loosing focus.
The itemsource should not be Two way. One way will do since you probable will be binding to an observable collection. This will only be set once from your datacontext. This will automatically handle the adding and removing of items to your collection.
I'd add your code like this:
<ListBox Margin="10,0,0,0" Width="200" HorizontalAlignment="Left" ItemsSource="{Binding Commands}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Where should I set Binding TwoWay?
You should set this Mode for TextBox like this:
<TextBox Text="{Binding Path=Name, Mode=TwoWay}" />
If I'm not mistaken, the Text property is listed TwoWay mode by default. Therefore, it's construction is not required.
From MSDN:
When used in data-binding scenarios, this property uses the default update behavior of UpdateSourceTrigger.LostFocus.
This means that updates the properties were visible at once, you need to set the property UpdateSourceTrigger to PropertyChanged:
<TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
So if I set Binding in ItemSource - is it inherited in TextBox?
No, inheritance will not be, because settings of Binding unique for each dependency property. Inheritance happens when using DataContext, but again, settings unique for each property.
I'm currently trying to do some binding inside of a datagrid but I'm having problems getting up to the level of DataContext of the view.
Here is the code:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Operators}"
ItemsSource="{Binding DataContext.OperatorList,ElementName=FilterGrid}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
Any ideas on whats wrong? The View's Viewmodel is connected in the code behind.
EDIT: The Binding that is not working is the ItemsSource binding shown above
When you use the DataTemplate of the DataGrid, you cannot use ElementName bindings as it won't resolve properly due to limitations in the resolution capabilities of FindControl within the DataGrid control hierarchy. You need to use a RelativeSource binding that travels up the control tree looking for a specific control type (which you need to determine - from your element name I assumed it was a DataGrid ancestor type).
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox
SelectedItem="{Binding Operators}"
ItemsSource="{Binding DataContext.OperatorList,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
See this SO post that shares some potentially related sample code using MVVM to access the DataContext of the UserControl host to populate a ComboBox ItemsSource.
I have a DataTemplate with a Combobox inside a ListView like this
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.Dimensions, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"
DisplayMemberPath="Description"
SelectedValuePath="Id"
SelectedItem="{Binding DimName}"/>
</DataTemplate>
The combobox is populated correctly, but it doesn't select the content according to underlying field (ie. Dimension.DimName).
Here's how the ListView is declared
<ListView
Name="lstCriteria"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Margin="5"
AlternationCount="2"
ItemContainerStyle="{StaticResource CriteriaItemStyle}"
ItemsSource="{Binding Source={StaticResource CriteriaList}}" DockPanel.Dock="Top"
IsSynchronizedWithCurrentItem="True">
If I replace combobox with a TextBlock it does show the DimName Field's value, like this
<TextBox Text="{Binding DimName}"/>
What am I missing ?
Does your DimName come directly from the Dimensions list?
By default, if a ComboBox's Items is set to a custom class, it will compare the SelectedItem to an item in the ItemSource by reference. It will not match the item if they do not refer to the exact same object in memory, even if the object's data is the same.
To get around that you can either set SelectedValue and SelectedValuePath instead of SelectedItem on your ComboBox, or you can overwrite the Equals() method of your DimName class to return true if an object's data is equal
Edit
In regards to your comment below, is DimName a Dimension object? If so then setting SelectedItem should work fine. If it's an long you'll need to set SelectedValue, not SelectedItem. If it's something else, you may need a converter to convert it into a Dimension object
As Rachel suggested, I added a new Property to my class called Dimension of class Dimension like this
public Dimension Dimension
{
get { return _dimension; }
set { _dimension = value; }
}
and then set SelectedItem="{Binding Dimension}" as follows,
<ComboBox ItemsSource="{Binding DataContext.Dimensions, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"
DisplayMemberPath="Description"
SelectedValuePath="Id"
SelectedItem="{Binding Dimension}">
</ComboBox>
The silly mistake I was making was,
As my combobox was populating correctly, I was hoping that WPF will somehow match the DimName content with one of the items in the ComboBox automatically, which is not possible.
I am DataTemplating a listbox's ItemSource to display a series of comboboxes. I want to give the DisplayMemberPath of the combo to a property, which is in a different source than its own ItemsSource. (Assuming DisplayMemberPath is just a string representing name of a property, I am getting this from the user). I have achieved this with a CollectionViewSource, but all the comboboxes are displaying the same list.
What I am expecting to have after data templating is to have comboboxes display,
ComboboxInstance1.DisplayMemberPath = PropertyMapOfEmployee in FilterControls[0]
ComboboxInstance2.DisplayMemberPath = PropertyMapOfEmployee in FilterControls[1]
Is this possible to achieve in XAML ?
Thanks. Mani
UserControl:
<Resources>
<CollectionViewSource x:Key="bindingSource" Source="{Binding BindingItems}"/>
<CollectionViewSource x:Key="FilterSource" Source="{Binding FilterControls}"/>
<DataTemplate DataType="{x:Type CustomTypes:FilterElement}">
<ComboBox ItemsSource="{Binding Source={StaticResource bindingEmp}"
DisplayMemberPath="{Binding Source={StaticResource FilterSource},
Path=PropertyMapofEmployee}" />
</DataTemplate>
<Resources>
---
<DockPanel>
<ListBox x:Name="lstBox" ItemsSource="{Binding FilterControls}" />
</DockPanel>
ViewModel:
List<FilterElement> FilterControls;
List<Employee> Employees
class FilterElement
{
string Caption;
String PropertyMapofEmployee
}
<ComboBox ItemsSource="{Binding Source={StaticResource bindingEmp}"
DisplayMemberPath="{Binding PropertyMapofEmployee}" />
I'm not sure you can do that in XAML. (Having the DisplayMemberPath point to a property that is on an object other than the DataContext). You may want to look at the RelativeSource Class to see if that would meet your needs.
Have you thought about providing a reference in your Employee object to the FilterElement and then hooking up to the binding the Employee.PropertyMapOfEmployee property that you've created?