I'm working with a window with several DataGrid's, and I'd like to process deletion event via a single command.
For this, I need to pass to that command the list of records, from which the record has to be deleted.
Here's what I mean:
<DataGrid Margin="0" HeadersVisibility="None"
ItemsSource="{Binding GroupExtednedDataList}"
... >
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="delete"
CommandParameter="{Binding:::
How do I bind from here to GroupExtednedDataList from ItemsSoruce?}" >
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
How do I bind from inside <Button Content="delete" to ItemsSource of the DataGrid?
Something like
{Binding ItemsSource, RelativeSource={RelativeSource AncestorType=DataGrid}}
Related
Consider this XAML:
<UserControl>
<TextBlock Text="{Binding NestedObject.Name}" TextWrapping="Wrap"/>
<DataGrid DataContext="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding NestedObject.Name}" />
</DataGrid.Columns>
</DataGrid>
</UserControl>
In the case of the TextBlock the object property would be correctly displayed, but when using it in a DataGrid, nothing is displayed.
This is odd since I call it the same way in both cases and I thought that when no data context was specified it was falling back to the parent data context.
Am I missing something in the declaration ?
Note
I'm using the UserControl in the MainWindow and an object with a NestedObject property is assigned to its data context. Also, Name is implementing INotifyPropertyChanged.
You generally bind a column in a DataGrid to a property of an item in the DataGrid's ItemsSource, i.e. your current binding will only work if the ItemsSource property is bound or set to an IEnumerable<T> and the type T has a SomeObject property.
If you want to to bind to a property of another object, you could use a {RelativeSource} to explictly specify the source of the binding:
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext.SomeObject.Name, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding DataContext.SomeObject.Name, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Name" Binding="{Binding SomeObject.Name}" />
</DataGrid.Columns>
</DataGrid>
I have a datagrid where the first column is constant for all the rows.
I would like following behavior:
When user double-clicks on any cell of the row (excluding first cell), action A is invoked knowing which row is selected. This is event-based (triggers an event).
When user double-clicks on first cell of any row, action B is invoked knowing which row is selected.
To do this, I wrote following code:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding source}" MouseDoubleClick="doubleClick">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="♣" Foreground="{Binding Path=color}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding FirstCellCommand}" CommandParameter="{Binding SelectedItem, ElementName=dataGrid}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Label" Binding="{Binding label, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
</DataGrid>
Point (1.) works fine, but (2.) does not trigger the action.
Am I missing a point here ?
Just in case anyone would have similar question: I have not found exactly what I want, yet! but there is a work around using code-behind.
It works for me as follows:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding source}" MouseDoubleClick="doubleClick">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="♣" Foreground="{Binding Path=color}" MouseDown="this_MouseDown"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Label" Binding="{Binding label, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
</DataGrid>
I removed the Interaction.Triggers and added MouseDown to the TextBlock.
If anyone would provide an answer using binding, I would appreciate.
Here's my problem : I have a DataGrid with a list of objects as DataSouce. In one column, I need to display several images. These images are issued from a property (named Images) of my objects and I have to filter them using a method from my viewModel.
Here's my XAML :
<DataGrid ItemsSource="{Binding MyObjects}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}"></DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding MyMethodToFilterImages}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Source}"></Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
So, how can I do that ?
Thanks in advance.
I'm trying to learn MVVM (Using MVVMLight Toolkit). But i'm stuck.
In ViewModel have an ObservableCollection
private ObservableCollection<Phone> _phoneNumbers;
public ObservableCollection<Phone> PhoneNumbers
{
get { return _phoneNumbers; }
private set
{
_phoneNumbers = value;
}
}
In ViewModel constructor fill it in such way PhoneNumbers = new ObservableCollection<Phone>(Guest.Person.Phones);
In view have
<DataGrid x:Name="PhoneNumbersDataGrid" HorizontalAlignment="Left" Grid.Column="3" Grid.Row="11" VerticalAlignment="Top" Height="86" Width="auto" ItemsSource="{Binding PhoneNumbers, Mode=OneWay}" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding PhoneNumber}" Header="Phone Number" IsReadOnly="True"/>
<DataGridTemplateColumn Header="Delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding Guest.DeletePhoneCommand, Mode=OneWay, Source={StaticResource Locator}}">Delete</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
In DeletePhoneCommand I'm trying to change PhoneNumbers e.g.
PhoneNumbers = new ObservableCollection<Phone>();
RaisePropertyChanged("PhoneNumbers");
Collection became empty but datagrid displays filled collection without any changes. "get" of Collection fires only when view is loading. Even when i RaisePropertyChanged("PhoneNumbers") it doesn't fire.
What am I doing wrong?
If you want to notify the changes to your collection you should use Mode = TwoWay
Two way will enable any change in object is reflected to the UI and any change in UI is reflected in the object.
<DataGrid x:Name="PhoneNumbersDataGrid" HorizontalAlignment="Left" Grid.Column="3" Grid.Row="11" VerticalAlignment="Top" Height="86" Width="auto" ItemsSource="{Binding PhoneNumbers, Mode=TwoWay}" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding PhoneNumber,Mode=TwoWay}" Header="Phone Number" IsReadOnly="True"/>
<DataGridTemplateColumn Header="Delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding Guest.DeletePhoneCommand, Mode=OneWay, Source={StaticResource Locator}}">Delete</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
If I'm not mistaken, the binding is broken when you reinitialize the collection. to fix this you will have to work on the already initialized collection. e.g :
clear the list using the
PhoneNumbers.Clear()
to add to the list, using
PhoneNumbers.Add(item)
you don't need to raise the property changed event to update the list in the UI when you're using ObservableCollection. You will need it if you change a property of the item on the list.
at first clear the list with
Clear()
then add item
PhoneNumbers.Add(item)
The ComboBoxes in question are inside a DataGrid's column and have been defined as follows:
<DataGridTemplateColumn Header=" Right Column ">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Caliber, RelativeSource={RelativeSource AncestorType=Window}}" DisplayMemberPath="Thicknesss" SelectedItem="{Binding Thickness, UpdateSourceTrigger=PropertyChanged" SelectionChanged="ComboBox_SelectionChanged">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
TIA
Probably you are looking for DataTriggers which can be set on Style of the ComboBox and depending on the condition the ComboBox can be enabled or disabled.
The ComboBoxes in question are inside a DataGrid's column and have been defined as follows:
<DataGridTemplateColumn Header=" Right Column ">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Caliber, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}" DisplayMemberPath="Thickness" SelectedItem="{Binding Thickness, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" >
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Link
http://social.technet.microsoft.com/wiki/contents/articles/19493.wpf-best-combobox-tutorial-ever.aspx#DataGridTemplateColumn_CellTemplate