WPF DataBinding in a DataGrid Header - c#

I'm trying to bind a ViewModel property to a Checkbox in the header of a DataGrid.
The checkbox binds just fine if I stick it randomly in the window, but if its in the header of the datagrid, it doesn't bind in either direction.
The data in the DataGrid binds fine as well.
The issue seems to be that the HeaderTemplate isn't binding to the main view model. I assume its binding ItemSource.
How do I bind to the view model in the header?
<DataGrid ItemsSource="{Binding Channels}" AlternationCount="2" Grid.IsSharedSizeScope="True" AutoGenerateColumns="False" AlternatingRowBackground="{StaticResource GroupBackgroundBrush}" SelectedIndex="{Binding Path=CursorChannelInt}" >
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Test}">Test Chkbox</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=stuff}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>

This works, by going to the Window, getting its DataContext, and going from there. Is there a better way?
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Test}">Test Chkbox</CheckBox>

The above answers were not working in my case, so I solved using Initialized event trigger
.xaml
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox Initialized="CheckBox_Initialized" IsChecked="False">Test Chkbox</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
.xaml.cs
private CheckBox cb_All = null;
private void CheckBox_Initialized(object sender, EventArgs e)
{
cb_All = (CheckBox)sender;
}
private void Function()
{
if(cb_All != null)
cb_All.IsChecked = true; //or false
}
It is sooo late, spending several years.. but I hope this may help to anyone:)

if the property is not in the collection, you have perhaps a nice answer, other rewrite for the same would be to use the ElementName to shorten the binding syntax
sample
<DataGrid ItemsSource="{Binding Channels}" AlternationCount="2" Grid.IsSharedSizeScope="True" AutoGenerateColumns="False" AlternatingRowBackground="{StaticResource GroupBackgroundBrush}" SelectedIndex="{Binding Path=CursorChannelInt}"
x:Name="dGrid">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding DataContext.Test, ElementName=dGrid}">Test Chkbox</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=stuff}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
above sample is based on the assumption that the property Test is in the same VM as Channels property.

Related

WPF Datagrid: Binding is not working for DataGridTemplateColumn

i'm faily new in WPF and got a problem with a binding not refreshing the UI.
If i open the window, the datagrid fills as it should. I have an object with refences to 2 other that where compared beforehand, named "Original" and "Vergleicher".
The method "MenuItem_OnClick" copies the value vom "Vergleicher" to "Original". In the binded list this works, i can see the changed values in the debugger, but the UI ignores it.
Set the datacontext in window:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
The actual datagrid:
<TabItem Header="Unterschiede" Visibility="{Binding UiLeistungUnterschiedlich,
Converter={StaticResource EmptyListHiddenConverter}}" Selector.Selected="OnTabSelected">
<Border Style="{StaticResource DropBorderStyle}">
<DataGrid ItemsSource="{Binding UiLeistungUnterschiedlich}"
SelectionChanged="GridHalter_SelectionChanged" SelectedIndex="0"
AutoGenerateColumns="False" SelectionMode="Single" CanUserAddRows="False">
<DataGrid.Columns>
<other Datagridtextcolumns>
<DataGridTemplateColumn Header="Straße">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type abrechnungen:HalterVergleich}">
<StackPanel Background="{Binding BindsDirectlyToSource=True, ConverterParameter=Strasse,
UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BackgroundColorConverter}}">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="In Halter übernehmen" Click="MenuItem_OnClick" Tag="Strasse"/>
</ContextMenu>
</StackPanel.ContextMenu>
<TextBlock Text="{Binding Path=Original.Strasse, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Path=Vergleicher.Strasse, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Border>
</TabItem>
The Border is used to apply a Dropshadow.
The copy method:
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
{
if (!(sender is MenuItem {DataContext: HalterVergleich vergleich} item))
{
return;
}
if (!vergleich.Setzen(item.Tag?.ToString(), Setzen.ZuOriginal))
{
return;
}
OnPropertyChanged(nameof(UiLeistungUnterschiedlich));
}
Sidenote: If anyone knows a way to avoid the use of "Tag" (to call "MenuItem_OnClick") and "ConverterParameter" with explizit values, i would gladly hear it.

Hiding column in datagrid depending on conditials

I need to display or hide one of data grid's column dynamically depending on condition.
As I know column doesn't present in a logical or visual data grid tree, so I decided to replace it to static resource
What I have
View
(Hided namespaces for clear)
<UserControl Name="UserControl">
<UserControl.Resources>
<DataGridTemplateColumn x:Key="ProblemColumn"
Visibility="{Binding DataContext.IsDisplayed, Source={x:Reference UserControl}, Converter={StaticResource BooleanToVisibilityConverter}}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="myModels:SomeModel">
<DataGrid ItemsSource="{Binding SomeViewModel}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="myModels:AnotherModel">
<Border>
<TextBlock Text="{Binding Text}"
VerticalAlignment="Center"
HorizontalAlignment="Right"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</UserControl.Resources>
<Grid>
<ScrollViewer>
<DataGrid ItemsSource="{Binding AnotherItems}">
<DataGrid.Columns >
<DataGridTemplateColumn>
...
</DataGridTemplateColumn>
<StaticResource ResourceKey="ProblemColumn"/>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</Grid>
ViewModel
There just my property where I explicitly set value for hiding column
public bool IsDisplayed => false;
So now property is binding properly and it returns value, but no any changes on UI, column still present in datagrid and I can see it even though the value of property is set to false.
What can I missed?
You can hide it by removing a certain column in code behind.
<Grid Loaded="OnGridLoaded">
<ScrollViewer>
<DataGrid ItemsSource="{Binding AnotherItems}" x:Name="MyDataGrid">
<DataGrid.Columns >
<DataGridTemplateColumn x:Name="MyColumn">
...
</DataGridTemplateColumn>
<StaticResource ResourceKey="ProblemColumn"/>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</Grid>
Code behind:
private void OnGridLoaded(object sender, RoutedEventArgs e)
{
var vm = (sender as Grid)?.DataContext as FooVm;
if ((vm != null)
&& (vm.IsDisplayed == false))
{
MyDataGrid.Columns.Remove(MyColumn);
}
}

MVVM WPF Datagrid TemplateColumn Combobox Selected Item Not Working

I am trying to bind some data to a datagrid using the MVVM pattern with WPF. I have confirmed that the datagrid is populating and indeed, that the specific value (Gender) is populated. I've also tried every fix that I could find online (including other questions on this site) that's why I am seeking out an answer here.
<DataGridTemplateColumn Header="Gender" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Genders}" SelectedItem="{Binding Gender, UpdateSourceTrigger=PropertyChanged}" IsSynchronizedWithCurrentItem="True">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Things I've tried: Mode=TwoWay, UpdateSourceTrigger=PropertyChanged", IsSynchronizedWithCurrentItem="True". Although, I am not a super experienced WPF and MVVM programmer, so it could be something simple that I just don't know about. My models seem to be working elsewhere and they implement observable/are in observable collections where applicable.
Edit: I got it sorted out. Here is the code that worked for my issue (in case someone else has a similar problem).
<DataGridTemplateColumn Header="Gender" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Genders, RelativeSource={RelativeSource FindAncestor, AncestorType = Window}}" SelectedItem="{Binding Gender, UpdateSourceTrigger=PropertyChanged}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Assuming you DataGrid's DataContext is the Patient object, try using a RelativeSource binding to point at the DataGrid:
<DataGridTemplateColumn Header="Gender" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=DataContext.Genders}"
SelectedItem="{Binding Gender, UpdateSourceTrigger=PropertyChanged}"
IsSynchronizedWithCurrentItem="True">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Binding ObservableCollection<Tuple<Object, List<Object>>> to DataGrid

I have an ObservableCollection with a Tuple and want to bind it to my DataGrid. This is the ObservableCollection:
ObservableCollection<Tuple<NetworkItem, List<NetworkItem>>> ListNetworkItems = new ObservableCollection<Tuple<NetworkItem, List<NetworkItem>>>();
And here is my DataGrid:
<DataGrid x:Name="NetworkDataGrid"
ItemsSource="{Binding ListNetworkItems}" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Sender">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Item1.Device.Name, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Receiver">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Item2.Device.Name, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The problem is, how can I bind the second item in my ObservableCollection? This is a list of several devices which belows to the item1 in the ObservableCollection. My DataGrid should look like:
Sender Receiver
Device 1 Device 2
Device 3
Device 5
Device 2 Device 1
Device 3 Device 2
Device 4
You need another list control of some kind in the cells in column 2 to display your sub-list.
Something like this should work:
<DataGridTemplateColumn Header="Receiver">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Item2}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Device.Name, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
This will create an ItemsControl in every cell in your Receiver column to hold the list of items within the sub-list.

How to get checkbox in the DataGridTemplateColumn?

I'm creating a window for user delete multiple registers of database using DataGrid for show data and a Button for execute delete
So I putted a DataGridTemplateColumn in the DataGrid and CheckBox in this DataGridTemplateColumn
<DataGrid Name="WordList" Margin="10" Width="230" AutoGenerateColumns="False"
SelectionMode="Single" SelectionChanged="WordList_SelectionChanged"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="WordChecked" HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding Path=Word}" Header="Word" Width="1*"
IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
Please, how to can I access this CheckBox with C# for check it is checked or not?
My recommended approach is to have a List<Item> that is held in the ViewModel and whenever you check the CheckBox in the row the datagrid's SelectedItem will be set and you add the item that was selected to the List. Then when the button is clicked, you delete all the records that are in the List.
Ideally you also want to implement this using Commands.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked= "{Binding checked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Click="CheckBox_Click"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
int index = DGItems.SelectedIndex;
DataRowView drv = (DataRowView)DGItems.Items[index];
}

Categories

Resources