WPF - MVVM : Bind on method with parameter depending on datacontext property - c#

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.

Related

Access Editing Cell of DataGrid in C# wpf

I made a Datagrid with XAML:
<DataGrid Name="dataGridBlockRow" Width="Auto" AutoGenerateColumns="False" VirtualizingStackPanel.IsVirtualizing="False"
CanUserReorderColumns="False" CanUserAddRows="false" CanUserDeleteRows="false" VerticalScrollBarVisibility="Visible"
BeginningEdit="dataGridBlockRow_BeginningEdit"
LoadingRow="gridColumns_LoadingRow" Grid.Column="1" Grid.Row="2">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Row Number" MinWidth="120" Width="1*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="0" Text="{Binding Path=RowNumber}">
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<toolkit:UIntegerUpDown Name="InputNumber" Value="{Binding Path=RowNumber, Mode=TwoWay}" AllowTextInput="False">
</toolkit:UIntegerUpDown>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Tree Count" MinWidth="120" Width="1*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="0" Text="{Binding Path=TreeCount}">
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<toolkit:UIntegerUpDown Name="inputTree" Value="{Binding Path=TreeCount, Mode=TwoWay}">
</toolkit:UIntegerUpDown>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
in c# code I added a List to my DataGrid:
List<BlockRow> blockRowList = new List<BlockRow>();
dataGridBlockRow.ItemsSource = blockRowList;
I want to Access the input control InputNumber and InputTree.
How can I access the current Editing Cell Input TextBox?
In WPF better to avoid change controls inside DataTemplate.
But if you want to get reference you can use FindName method of dataTemplate.
public static Control GetControlFromCellEditingTemplate(this DataGridColumn column, string controlName)
{
DataTemplate template = column.CellEditingTemplate;
return template.FindName(controlName, column);
}
you can use it like
var inputNumberUpDown = ((DataGridColumn)dataGridBlockRow.Columns[0]).GetControlFromCellEditingTemplate("InputNumber") as UIntegerUpDown;
var inputTreeUpDown = ((DataGridColumn)dataGridBlockRow.Columns[1]).GetControlFromCellEditingTemplate("inputTree") as UIntegerUpDown;

Set Binding of DataGridTextColumn's TextBlock

I'm trying to change the binding for the "Text" property for a TextBox inside of a DataGrid. Consider the following code:
<DataGrid Name="CoreView837" HorizontalAlignment="Left" Height="366" VerticalAlignment="Center" Width="792"
AutoGenerateColumns="False" SelectionUnit="Cell" SelectionMode="Extended" VerticalScrollBarVisibility="Auto" ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn x:Name="ClaimNumber" Header="Claim Number" Width="350" Binding="{Binding ClaimNumber}">
</DataGridTextColumn>
<DataGridTemplateColumn x:Name ="Parent837" Header="837 Segment" Width="300" ClipboardContentBinding="{Binding SegmentText}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ScrollViewer MaxHeight="100">
<TextBlock x:Name="Segment837" Text="{Binding SegmentText}" TextWrapping="Wrap"/>
</ScrollViewer>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Errors" Width="350" ClipboardContentBinding="{Binding ErrorText}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ScrollViewer MaxHeight="100">
<TextBlock Text="{Binding ErrorText}" TextWrapping="Wrap"/>
</ScrollViewer>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I want to change the binding of the TextBlock "Segment837" in the code behind to a new binding, like below:
Segment837.Binding = new Binding("Value");
However, it seems that I can't change the Text binding of the TextBlock directly. It seems I can only select "Parent837."
Can anyone suggest to me how to change the binding either directly or even a better way? Right now I have the binding set for when a text file's broken segments are successfully loaded, but I wanted to change the binding of the TextBlock for instance in the case that it fails and I want to return alternative data.

Losing DataContext when using Datagrid in UserControl

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>

Bind datagridcell to display content of a collection

I want to display the content of a collection in a datagrid cell. What is special, is that the columnheaders are bound to a specific item of collection (i.e. one for each workday). The cell content should be a textbox for each employee in the according collection. The columnheaderpart is working fine.
The hierarchy of the viewmodel is as follows:
Planning holds a collection of Projects and a collection of Days(used to get the columnheader)
Project holds a collection of Days
Day holds a collection of Employees
However, the following code is not working. From debugging I'm lead to believe that the it is a problem with binding, as there is no access to the employees collection. Any idea why this is not working?
<DataGrid Grid.Row="0" Grid.Column="1" AutoGenerateColumns="False" ItemsSource="{Binding Planning.Projects}" ColumnHeaderHeight="50">
<DataGrid.Columns>
<DataGridTextColumn Width="200" Header="Project" Binding="{Binding Projectname}">
</DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding DataContext.Week.Days[0].Id, RelativeSource={RelativeSource AncestorType=DataGrid}}" HorizontalAlignment="Center">
<Run Text="{Binding Mode=OneWay, StringFormat=ddd}"/>
<LineBreak/>
<Run Text="{Binding Mode=OneWay, StringFormat=dd.MM.yyyy}"/>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding DataContext.Planning.Projects.Days[0].Employees}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The DataContext for the Cell DataTemplate is probably one instance of Project, because the ItemsSource for the DataGrid is a collection called Projects.
Therefore, in the CellTemplate, any Path on a Binding should be referring to a property of a Project, just as in the Projectname column:
<DataGridTextColumn
Width="200"
Header="Project"
Binding="{Binding Projectname}">
Project is the DataContext for each column. The above Binding works because Projectname is a property of Project.
So this should work:
<ItemsConttrol
ItemsSource="{Binding Days[0].Employees}"
...
Project has a Days collection. You want the Employees collection from the first item in Days for this project.

How to bind to the ItemsSource of a DataDrid from inside DataRow?

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}}

Categories