Set Binding of DataGridTextColumn's TextBlock - c#

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.

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;

DataGrid CellEditEnding event not firing on a cell editing inside DataGridTemplateColumn

In the MyDatagrid_CellEditEnding(...) event (shown below) I am capturing the edited value of a cell whenever a cell of one of the three columns is edited by a user. After editing cell in second or third column, when I move out of that cell, I can see the CellEditEnding event getting called. But the same is not true for the first column that is a DataGridTemplateColumn column. That is, when I change a date in any cell in the first DataGridTemplateColumn, and move the cursor out of the cell, the CellEditEnding event is not called.
Question: What I may be missing here and how can we make it work? I have seen similar issues and their solutions online (such as this and this), so I'm not sure what I may be missing here.
Note: I'm using latest versions of VS2019 and .NET Core 3.1 on Windows 10 vs1903 - Pro
<Window x:Class="MyTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
.....
Title="MainWindow">
<Grid>
<DataGrid x:Name="MyDatagrid" AutoGenerateColumns="False" SelectionMode="Single" CellEditEnding="MyDatagrid_CellEditEnding">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Date Modified">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="btnTest" Content="Test" HorizontalAlignment="Left" VerticalAlignment="Top" Click="btnTest_Click"/>
</Grid>
</Window>
Code:
......
......
string _sDateModified;
string _sFirstName;
string _sLastName;
.....
.....
private void MyDatagrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
DataGridColumn c = e.Column;
if (c.Header.ToString() == "Date Modified")
_sDateModified = (e.EditingElement as TextBox).Text;
else if (c.Header.ToString() == "First Name")
_sFirstName = (e.EditingElement as TextBox).Text;
else if (c.Header.ToString() == "Last Name")
_sLastName = (e.EditingElement as TextBox).Text;
}
You are editing the DatePicker in the CellTemplate and this doesn't cause the CellEditEnding event to fire. The CellTemplate is not supposed to contain any input controls.
Replace the DatePicker in the CellTemplate with a TextBlock:
<DataGridTemplateColumn Header="Date Modified">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DateModified, StringFormat=yyyy-MM-dd}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified, UpdateSourceTrigger=LostFocus}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Or set the IsEnabled property of the DatePicker in the CellTemplate to false. Either way, you'll have to enter the edit mode by double clicking on the cell before you can expect the CellEditEnding event to fire.
Try this:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified, UpdateSourceTrigger=LostFocus}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

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>

WPF DataGrids With Images I need more than 1 column

So far I have this code:
<DataGrid HeadersVisibility="None" ItemsSource="{Binding Pics}" AutoGenerateColumns="False" Margin="0,0,-0,0" Width="auto">
<DataGrid.Columns>
<DataGridTemplateColumn Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Image Height="120" Source="{Binding path}" />
<TextBlock x:Name="box" Text="{Binding title}"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Now this works quite well, problem is it places the images like this:
X
Title
X
Title
X
Title
Where as I'd like something that utilizes more than one column, I want multiple columns all ultilizing my images, but not mirroring my first column. I would like the images to keep using this row until they hit the border of the window and make a new row automatically
I really hope this is possible and feasible to do, thanks for any help.
Sorry if this is a dumb question, still grasping WPF.
Add the orientation horizontal to stackPanel
<StackPanel Orientation = "Horizontal">
<Image Height="120" Source="{Binding path}" />
<TextBlock x:Name="box" Text="{Binding title}"></TextBlock>
</StackPanel>
check if this works

Filter WPF DataGrid values from TextBox in Column Header

I followed the advice in the following link (filter wpf datagrid values from a textbox) to create Figure A. Which allows me to filter the DataGrid based on what is in the TextBox when I press the Button.
However once I move the Button and TextBox within the column headers of the DataGrid like in Figure B. The Button still works but the Binding of the TextBox doesn't as it is showing up null within the code.
http://i42.tinypic.com/2quivpx.png
The only real change between what was done in the link is my XAML where I have put my TextBox and Button within the DataGridTemplateColumn Header.
<Grid DataContext="{Binding ElementName=UI}" >
<DataGrid AutoGenerateColumns="False" Height="184" HorizontalAlignment="Left" Margin="12,23,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="384" ItemsSource="{Binding DataGridCollection}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Name="IDSearcBox" Text="{Binding FilterString}" Width="100"/>
<Button Name="IDSearchButton" Click="IDButton_Click" Content="I" Width="30"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ID}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Name="NameSearchBox" Text="{Binding FilterString}" Width="100"/>
<Button Name="NameSearchButton" Click="NameSearchButton_Click" Content="N" Width="30"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="SomethingElse" Binding="{Binding SomethingElse}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
Any assistance on this would be greatly appreciated! I've been scratching my brain all day on this one!
(I would have posted on the other post for some advice but I couldn't see any option!)
The Textbox is now inside the DataGrids ItemSource DataContext,
Try setting the DataContext of the TextBox back you your out to the UI DataContext
<TextBox Name="IDSearcBox" Text="{Binding FilterString, ElementName=UI}"

Categories