Binding ancestor element in WPF [duplicate] - c#

This question already has answers here:
Binding Visibility for DataGridColumn in WPF
(4 answers)
Closed 4 years ago.
I am struggling to hide columns of a Datagrid by binding the Visibility property to a property of the viewModel. ItemsSource works fine and I have many lines in the grids, to the Datacontext is set properly. Can you please help me with what I am doing wrong ? Thanks
<StackPanel>
<DataGrid ItemsSource="{Binding SortedPlanning}" IsReadOnly="True" AutoGenerateColumns="False" CanUserResizeRows="False">
<DataGrid.Columns >
<DataGridTextColumn Header ="NNI" Binding="{Binding SortedPlanning.Nni}" Width="80" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}, Path=ColumnVisibility}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header ="Nom" Binding="{Binding LastName}" Width="120" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=ColumnVisibility}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header ="Prénom" Binding="{Binding FirstName}" Width="80" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=ColumnVisibility}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGridTextColumn>
<DataGridTextColumn Header ="Campagne" Binding="{Binding Campaign}" Width="120">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid>
</StackPanel>
View model :
public interface IPlanningViewModel : IDisposable
{
ObservableCollection<PlanningEntry> SortedPlanning { get; }
Visibility ColumnVisibility { get; }
bool FilterGrid { get; set; }
DateTime FromDate { get; set; }
DateTime ToDate { get; set; }
}
I expect columns "NNI", "Nom" and "Prénom" to be bound to the ColumnVisibility of the VM, but it does not happen.

You will have use below syntax.
It should resolve your issue.
<DataGridTextColumn Visibility="{Binding Path=DataContext.ColumnVisibility, RelativeSource={RelativeSource AncestorType=DataGrid}}" />

Related

DataGrid Onselection some Cells dosen't get highlighted

I have a WPF Data grid that turn some Cells Red on a Error in the Data. Since I implemented this Binding to the Cells. Some of The Cells Text turns White but It Doesn't show The Selection on this Certain Cells has anyone a Idea why this is happening?
Picture of DataGrid with Selection Failure
<DataGrid Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="6" x:Name="DgCheckedEdeFile"
AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn Header="Zeile" IsReadOnly="True" Width="auto"
Binding="{Binding Path=Row}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding Path=Row.Color}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Device-Object-Instance" IsReadOnly="True" Width="*"
Binding="{Binding Path=deviceObjectInstance}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding Path=deviceObjectInstance.Color}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Object-Name (AKS)" IsReadOnly="True" Width="*"
Binding="{Binding Path=objectName}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding Path=objectName.Color}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Object-Type" IsReadOnly="True" Width="*"
Binding="{Binding Path=objectType}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding Path=objectType.Color}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Object-Instance" IsReadOnly="True" Width="*"
Binding="{Binding Path=objectInstance}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="{Binding Path=objectInstance.Color}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>

MVVM DataGrid with Summary Line

I've been working on getting a simple grid setup and I'm having issues getting a summary line either above or below the DataGrid. Is their some some way to get total counts in the datagrid for specifict columns?
Here is what I have:
<Window xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
x:Class="TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Test Window" Height="645" Width="900">
<StackPanel Orientation="Vertical">
<DataGrid Height="500" ItemsSource="{Binding GridDetails}" HorizontalAlignment="Left" VerticalAlignment="Top" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn x:Name="Name" Header="Name" Binding="{Binding Path='Name', Mode=OneTime}" IsReadOnly="True" Width="200" />
<DataGridTextColumn x:Name="ID" Header="ID" Binding="{Binding Path='ID', Mode=OneTime}" IsReadOnly="True" Width="100">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn x:Name="NumClaims" Header="Claims" Binding="{Binding Path='NumClaims', Mode=OneTime}" IsReadOnly="True" Width="100">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn x:Name="NewClaims" Header="New Claims" Binding="{Binding Path='NumNewClaims', Mode=OneTime}" IsReadOnly="True" Width="80">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="{Binding NumNewClaims}"/>
</Style>
</DataGridTextColumn.CellStyle>
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Window>
In the View Model
private ObservableCollection<GridDetail> _gridDetails;
public ObservableCollection<GridDetail> GridDetails
{
get { return _gridDetails; }
set { SetProperty(ref _gridDetails, value); }
}
private int _totalClaims;
public int TotalClaims
{
get { return _totalClaims; }
set { SetProperty(ref _totalClaims, value); }
}
private int _totalNewClaims;
public int TotalNewClaims
{
get { return _totalNewClaims; }
set { SetProperty(ref _totalNewClaims, value); }
}
The trouble I'm having is figuring out how to put the totals I've been tracking in the view model in the column header. This is my preferred method but I could also work with a summary row that is frozen to the top of the grid if that is simpler to implement.
Any suggestions would be greatly appreciated.
You want to create a custom column header for each column. Then, bind the TextBlock with the property in the ViewModel. However, you need to play with the DataContext to make it work. Let's go by steps.
A custom header would be like this:
<DataGridTextColumn x:Name="NumClaims" Binding="{Binding Path='NumClaims', Mode=OneTime}" IsReadOnly="True" Width="100">
<DataGridTextColumn.Header>
<TextBlock Text="Claims" />
</DataGridTextColumn.Header>
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
Now this would be the same as you have right now, but now you can add more things to the header, such as a StackPanel.
<DataGridTextColumn.Header>
<StackPanel>
<TextBlock Text="Claims" />
<TextBlock Text="35"/> <!-- Dummy value -->
</StackPanel>
</DataGridTextColumn.Header>
And if, as in your case, you would like to bind a property from your ViewModel, you would write
<DataGridTextColumn.Header>
<StackPanel>
<TextBlock Text="Claims" />
<TextBlock DataContext="{Binding RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}, Path=DataContext}" Text="{Binding TotalClaims, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataGridTextColumn.Header>
I hope that this helps.

WPF DataGrid trigger on other cell value

I have DataGrid:
<DataGrid x:Name="PART_DataGrid"
ItemsSource="{TemplateBinding Items}"
AutoGenerateColumns="False"
Margin="2,25,2,2">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Language" Width="SizeToCells" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Path=Language, Mode=OneWay}"
ItemsSource="{Binding LanguagesSource, RelativeSource={RelativeSource AncestorType=UserControl}}"
FontSize="16"
IsEnabled="False">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=test }" Value="">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Translation" Width="SizeToCells" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="TranslationValueTB"
Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}"
BorderThickness="0"
FontSize="16" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
And I want to set that first column ComboBox will be enabled when second TextBox.Text is empty, I have tried different binding methods but none of them have worked. So how can I do that?
Bind to the Value source property that the TextBox in the second column is bound to:
<DataGridTemplateColumn Header="Language" Width="SizeToCells" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Path=Language, Mode=OneWay}"
ItemsSource="{Binding LanguagesSource, RelativeSource={RelativeSource AncestorType=UserControl}}"
FontSize="16"
IsEnabled="False">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Value}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
<DataTrigger Binding="{Binding Value}" Value="">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Also make sure that the class where the Value property is defined implements the INotifyPropertyChanged interface and raises the PropertyChanged event in the setter of the Value property.
Remove the IsEnabled = false from combobox and do the same in the setter as follows, and do the binding as like follows,
<ComboBox.Style>
<Style TargetType="ComboBox">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=Item.Name }" Value="{x:Static sys:String.Empty}">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
Item.Name - > this is the property you need to check

C# WPF DataGrid.RowStyle set column style

Is it possible to affect a style/Behaviorto a specified column in a specified row in WPF C#?
Right now I have this:
<DataTrigger Binding="{Binding Path=Status}" Value="2">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="IsEnabled" Value="false" />
</DataTrigger>
The problem right now is, that the entire row is disabled. I would like just the first column to be disabled in some circumstances.
This is the column, I would like to disable:
<DataGridTemplateColumn Header="Details" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="ShowDetails">Details</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
This works (disabling 2nd column "Y" if value of "X" is 3):
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="X" Binding="{Binding X}"/>
<DataGridTextColumn Header="Y" Binding="{Binding Y}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding X}" Value="3">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
The solution:
<DataGridTemplateColumn Header="Details" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button IsEnabled ="{Binding boolEnabled}" Click="ShowDetails">Details</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Style WPF DataGrid Row on Binding Property

I have a data grid bound to a list of EventRecords. On the EventRecord object is a property IsAutoEvent. I'm trying to style the background color on the row depending on whether this property is true or not but the DataContext is not set up as I expect.
<DataGrid Name="EventGrid" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Events}" SelectedItem="{Binding SelectedEvent}" CanUserAddRows="False" SelectionMode="Single" SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Header="Start Time" Width="Auto" Binding="{Binding StartTime, StringFormat={}{0:hh:mm:ss}}" CellStyle="{StaticResource CenterAlignedDataGridCell}"/>
<DataGridTextColumn Header="Description" Width="*" Binding="{Binding Description}" CellStyle="{StaticResource CenterAlignedDataGridCell}"/>
<DataGridTextColumn Header="Comments" Width="*" Binding="{Binding Comment}"/>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsAutoEvent}">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
Currently, this doesn't do anything. I don't think the datacontext is right because, under DataTrigger, the {Binding} shows properties for the View (e.g. MainViewModel), not the DataGridRow (e.g. EventRecord), as I would expect.
Any thoughts?
you have not put the Value on DataTrigger
<DataTrigger Binding="{Binding Path=IsAutoEvent}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
Please add the Value to your DataTrigger
<DataGrid Name="EventGrid" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Events}" SelectedItem="{Binding SelectedEvent}" CanUserAddRows="False" SelectionMode="Single" SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Header="Start Time" Width="Auto" Binding="{Binding StartTime, StringFormat={}{0:hh:mm:ss}}" CellStyle="{StaticResource CenterAlignedDataGridCell}"/>
<DataGridTextColumn Header="Description" Width="*" Binding="{Binding Description}" CellStyle="{StaticResource CenterAlignedDataGridCell}"/>
<DataGridTextColumn Header="Comments" Width="*" Binding="{Binding Comment}"/>
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsAutoEvent}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>

Categories