Show Index of each element of an CollectionViewSource - wpf

I have a View and a Viewmodel.
The Viewmodel has a property of type ICollectionView which I instance a CollectionViewSource with the Source, which is an ObservableCollection<Foo>
Now on my view I have a Datagrid to show this info, and in my Datagrid.Columns I have a DataGridTemplateColumn, inside a DataGridTemplateColumn.HeaderTemplate and then a DataGridTemplateColumn.CellTemplate
Now inside my cell template for my 1st header, I want to show the index or element number of each element of my collection, the cell template is like this:
<DataGridTemplateColumn.CellTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path= DataContext.CurrentPosition}"></TextBlock>
</ItemContainerTemplate>
</DataGridTemplateColumn.CellTemplate>
Now my DataContext.CurrentPosition returns empty, I dont know if this is the correct property of the object to return the index.

Ok I have solved the issue by following Andy's answer in this thread: How to show row-number in first column of WPF Datagrid

Related

How to add a tooltip for a datagrid and show the converted value of the datagrid in tooltip?

I have DataGrid and one of the DataGrid columns looks like this.
<ig:TextColumn HeaderText="{Binding CARTONS, Source={StaticResource Messages}, Converter={StaticResource MessageConverter}}"
Key="Collumn1"
AllowToolTips="Always">
<ig:TextColumn.ToolTipContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Self}, Converter={StaticResource TransferCollumnToCrlfDelimitedList}}"/>
</DataTemplate>
</ig:TextColumn.ToolTipContentTemplate>
</ig:TextColumn>
The problem is I need show convert the column's value to a list of sub-value of the column. I tried using self. Obviously, it doesn't work.
How can I solve my task? Is any possible.
Remove SELF
Use just {Binding} and you will get the same DataContext as the parent control

Binding a list of String to a DataGridTemplateColumn's ComboBox

The question might seem quite easy but I can't get it and I tried everything I've found. It works for a list of class, since I can bind on one of my class' properties, but not for a simple ObservableCollection of String.
Here's my code in Xaml :
<DataGridTemplateColumn x:Name="VT" Header="VT" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding ListOfString}"
SelectedValuePath="ListOfString"
DisplayMemberPath="ListOfString"
ItemsSource="{Binding RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type UserControl}},
Path=DataContext.ListOfString}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
My code behind works fine since when I open the dropdown it displays as many rows as there are elements inside, but rows are empty. I also tried to work with the CellEditingTemplate thing like here but it has the same result in the best case. I think I'm getting wrong on those DisplayMemberPath properties and others, but I don't see what I should get inside.
So how can I correctly bind my ObservableCollection to my ComboBox ?
Thanks !
if your ListOfString looks like this:
public ObservableCollection<string> ListOfString {get;set;}
then you should simply remove the SelectedValuePath and DisplayMemberPath. because otherwise wpf looks for the Property ListOfString which does not exists on strings :)
<ComboBox SelectedItem="{Binding ListOfString}"
ItemsSource="{Binding RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type UserControl}},
Path=DataContext.ListOfString}"/>
and if this is not the case you should post the code for your ListOfString property.
btw you should rename the SelectedItem property or the collection property, because atm both named ListOfString.

ComboBox doesn't show current value of assigned field inside a ListView

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.

WPF Datagrid ComboBox DataBinding

Can anyone tell me why this works;
<DataGridTemplateColumn Header="Supplier">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox DisplayMemberPath="SupplierName" SelectedValuePath="SupplierID"
SelectedValue="{Binding SupplierID}"
ItemsSource="{Binding Path=DataContext.Suppliers, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
but this doesn't;
<DataGridComboBoxColumn Header="Combo" DisplayMemberPath="SupplierName" SelectedValuePath="SupplierID"
SelectedValueBinding="{Binding SupplierID}"
ItemsSource="{Binding Path=DataContext.Suppliers, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
Second snippet does not show the list of SupplierName on edit...
It's because a DataGridComboBoxColumn isn't a user interface element, but ComboBox is.
In the first example, because your ComboBox is part of the visual tree, RelativeSource can do what it's supposed to do: walk up the UI tree looking for the item you've asked for. But in the second example, the DataGridComboBoxColumn is a DependencyObject but it's not an actual UI element - it's an object that describes something about the UI element.
You could try using ElementName instead, and give a name to your root window. Or, you might be able to get away with just:
<DataGridComboBoxColumn ...
ItemsSource="{Binding Path=Suppliers}" />
The DataContext will flow down from the window to the grid, so unless you've overidden it with something else at this point in the UI, it'll still be available.
Or if that doesn't work, you might want to add the relevant collection to a resource dictionary so you can get it with a Source={StaticResource suppliers} in the binding.
The reason is that the ItemsSource for the DataGridComboBoxColumn can not be found.
You will need to use the RelativeSource Binding and point it to the correct DataContext AncestorType. This will take some trial and error to find the DataContext that contains your list to satisfy your ItemsSource.

Append DataGrid inside of DataGrids RowDetailsTemplate

this appears to bind, but rows in Details Grid are empty. Something is off/missing?
I've also tried {Binding SubCustomers}
SubCustomers is a List on parent object.
I am able to bind this way to single Fields such as FirstName etc.. just not the subcollection..
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Source=SubCustomers}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
The problem is that you are trying to bind to a property on the DataContext of the parent, not on that particular row. So, the DataContext of the RowDetails is the row item, and in order to get the parent's property, you need to use RelativeSource bindings. If you bind to the DataContext of the parent, you can then "dot-down" to the property you actually care about:
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="True"
ItemsSource="{Binding DataContext.SubCustomers, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>

Resources