Bind Tag of the TextBlock - c#

I have a DataGrid as shown in the image below:
In DataGrid at the third level Date column is a DataGridTemplateColumn.
Here is the code of the above mentioned Date Column:
<DataGridTemplateColumn Header="Date" Width="5*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding StringFormat='{}{0:dd/MM/yyyy}'}"
Tag= ?????? />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
As mentioned in the above code I want to bind Tag Property of TextBlock to the number of occurences of same date in this column.
Example of what I want:
Suppose I have 5 rows
Date | Tag
-------------+----------
20/08/2012 | 1
20/08/2012 | 2
21/08/2012 | 1
23/08/2012 | 1
20/08/2012 | 3
Suppose you don't have code then please give me the logic I will try to code it myself.
Update: Full code of datagrid shown in the above image
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding DataContext.Patients, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
SelectedItem="{Binding SelectedPatient}" RowDetailsVisibilityMode="VisibleWhenSelected"
IsReadOnly="True" SelectionMode="Single" SelectionUnit="FullRow" >
<DataGrid.Resources>
<Style x:Key="VerticalCenter" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"></Setter>
</Style>
<Style x:Key="VerticalAndHorizontalCenter" TargetType="FrameworkElement" >
<Setter Property="VerticalAlignment" Value="Center"></Setter>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
</Style>
<Style x:Key="VerticalAndHorizontalCenterTextBlock" TargetType="TextBlock"
BasedOn="{StaticResource VerticalAndHorizontalCenter}"/>
<Style x:Key="VerticalAndHorizontalCenterHeader" TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource VerticalAndHorizontalCenter}"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding PatientName}" Header="Patient Name" Width="25*"
ElementStyle="{StaticResource VerticalCenter}"/>
<DataGridTextColumn Binding="{Binding City}" Header="City" Width="15*"
ElementStyle="{StaticResource VerticalAndHorizontalCenterTextBlock}"
HeaderStyle="{StaticResource VerticalAndHorizontalCenterHeader}"/>
<DataGridTextColumn Binding="{Binding TypeSex.Value}" Header="Sex" Width="10*"
ElementStyle="{StaticResource VerticalAndHorizontalCenterTextBlock}"
HeaderStyle="{StaticResource VerticalAndHorizontalCenterHeader}"/>
<DataGridTextColumn Binding="{Binding Age}" Header="Age" Width="5*"
ElementStyle="{StaticResource VerticalAndHorizontalCenterTextBlock}"
HeaderStyle="{StaticResource VerticalAndHorizontalCenterHeader}"/>
<DataGridTemplateColumn Header="Delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Focusable="False" Command="{Binding DataContext.DeletePatientCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Image Source="Images/DeletePatient.png" />
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="False" IsReadOnly="True"
ItemsSource="{Binding DataContext.ReportNames,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
SelectedItem="{Binding DataContext.SelectedReportGroup,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
Margin="200,0,0,0" Width="500" HorizontalAlignment="Left">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}" Header="Report Name" Width="5*"
ElementStyle="{StaticResource VerticalCenter}"/>
<DataGridTemplateColumn Header="Delete" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Focusable="False" Command="{Binding DataContext.DeleteAllReportsOfATypeCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Image Source="Images/DeleteReport.png" Height="48" Width="48" />
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="False" IsReadOnly="True"
ItemsSource="{Binding DataContext.CorrespondingDates,
RelativeSource={RelativeSource FindAncestor,
AncestorType=Window}}"
SelectedItem="{Binding DataContext.SelectedReport,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Width="390" HorizontalAlignment="Right">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Date" Width="5*"
HeaderStyle="{StaticResource VerticalAndHorizontalCenterHeader}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding StringFormat='{}{0:dd/MM/yyyy}'}"
Tag="{Binding DataContext.Tag,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Style="{StaticResource VerticalAndHorizontalCenterTextBlock}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Edit" Width="1.5*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Focusable="False" Click="OpenTabForEdit"
Command="{Binding DataContext.EditSingleReportCommand,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Image Source="Images/EditReport.png" Height="48" Width="48" />
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Delete" Width="1.5*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Focusable="False"
Command="{Binding DataContext.DeleteSingleReportCommand,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Image Source="Images/DeleteReport.png" Height="48" Width="48"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Update 2 : The Class Structure
Similar for BloodChemistry and UrineAnalysis

It seems to me that you need a MultiBinding here, because you have two inputs: the entire collection, and the specific date you want to count. The XAML syntax would look something like this:
<TextBlock>
<TextBlock.Resources>
<my:ItemCountMultiConverter x:Key="ItemCountMultiConverter" />
</TextBlock.Resources>
<TextBlock.Tag>
<MultiBinding Converter="{StaticResource ItemCountMultiConverter}">
<Binding Path="." />
<Binding Path="ItemsSource" RelativeSource="{RelativeSource AncestorType=DataGrid}" />
</MultiBinding>
</TextBlock.Tag>
</TextBlock>
Then it is just a matter of implementing ItemCountMultiConverter : IMultiValueConverter to extract the date count from the collection:
public class ItemCountMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length < 2)
return DependencyProperty.UnsetValue;
var dateToCount = values[0] as DateTime?;
var source = values[1] as IEnumerable<Patient>;
if (!dateToCount.HasValue || source == null)
return DependencyProperty.UnsetValue;
source.Count(patient =>
patient.Haemogram.Any(haemogram => haemogram.Date == dateToCount)
|| patient.UrineAnalysis.Any(urine => urine.Date == dateToCount)
|| patient.BloodChemistry.Any(blood => blood.Date == dateToCount)
);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Related

How to get the `DataGridTextColumn` name and header of a `datagrid `through `code-behind`?

I am working with datagrid and I want to get the name and header of the datagridtextcolumn in code behind.
I have tried getting header value as
`Datagrid.Columns[0].HeaderText`
. But HeaderText is not working in my code.
Another way I tried is
var HeaderTexts = dataGridUserSalesRep.Columns.Select(e => e.Header.ToString()).ToList();.
This one also not working for me.
My Datagrid:
<DataGrid SelectionChanged="DatagridListviewSelectionChanged" Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type Grid}, Mode=FindAncestor}}" Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type Grid}, Mode=FindAncestor}}" x:Name="ListView" Style="{StaticResource DataGridListing}" >
<DataGrid.Columns>
<DataGridTemplateColumn Width="0.5*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<RadioButton GroupName="RadioButtonGroup" Style="{StaticResource DatagridRadioButton}" IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Width="2*" Header="{Binding SerialNo , Source={StaticResource Strings}}" x:Name="DataGridColumnSlNo" Binding="{Binding SlNo}" />
<DataGridTextColumn Width="2*" Header="{Binding ItemCode , Source={StaticResource Strings}}" x:Name="DataGridColumnHsn" Binding="{Binding ItemCode}" />
<DataGridTextColumn Width="2*" Header="{Binding itemName , Source={StaticResource Strings}}" Binding="{Binding ItemName}" />
<DataGridTextColumn Width="2*" Header="{Binding barcode , Source={StaticResource Strings}}" Binding="{Binding BarCode}" />
<DataGridTextColumn Width="2*" Header="{Binding hsnCode , Source={StaticResource Strings}}" Binding="{Binding HsnCodes}" />
<DataGridTextColumn Width="2*" Header="{Binding CountryOfOrigin , Source={StaticResource Strings}}" Binding="{Binding COO}" />
<DataGridTextColumn Width="2*" Header="{Binding Brand , Source={StaticResource Strings}}" Binding="{Binding Brand}" />
<DataGridTextColumn Width="2*" Header="{Binding shelf , Source={StaticResource Strings}}" Binding="{Binding Shelf}" />
</DataGrid.Columns>
</DataGrid>
I want both Name and header of all columns of this datagrid

C# - Popup is not displayed in second tab item in MVVM

I'm working in MVVM and i have two TabItem created in XAML. In the first one, the popup is displayed, but in the second one when I press the button corresponding to a column, the popup is not displayed.
Here is my code with the working Popup:
<Viewbox>
<Grid Height="359" Width="746">
<Popup Name="popupFilter" Placement="MousePoint" IsOpen="{Binding IsFilterOpen, Mode=OneWay}" StaysOpen="True" Width="200">
<Border Background="White" BorderBrush="Gray" BorderThickness="1,1,1,1">
<StackPanel Margin="5,5,5,15">
<ListBox x:Name="listBoxPopupContent"
Height="250"
ItemsSource="{Binding FilterItems}"
BorderThickness="0"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Item}"
Command="{Binding DataContext.ApplyFiltersCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBox}}}"
CommandParameter="{Binding IsChecked,
RelativeSource={RelativeSource Self},
Mode=OneWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Border>
</Popup>
<Grid HorizontalAlignment="Left" Height="261" Margin="0,63,0,0" VerticalAlignment="Top" Width="736">
<TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
<TabItem Header="Class">
<DataGrid x:Name="ClassViewDataGrid" ItemsSource="{Binding FilteredClassViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ClassName}">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Class" />
<Button Name="buttonClassViewClassFilter" Margin="10,0,0,0"
Command="{Binding DataContext.ShowFilterCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}">
<Button.ContentTemplate>
<DataTemplate>
<Image Source="/Images/filter.png" Width="10" Height="10" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
</StackPanel>
</DataGridTextColumn.Header>
and the tabItem that doesn't shows the popup:
<TabItem Header="Field">
<DataGrid x:Name="FielsdViewDataGrid" ItemsSource="{Binding FilteredFieldViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ClassName}">
<DataGridTextColumn.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Class" />
<Button Name="buttonFieldViewClassFilter" Margin="10,0,0,0"
Command="{Binding DataContext.ShowFilterCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}">
<Button.ContentTemplate>
<DataTemplate>
<Image Source="/Images/filter.png" Width="10" Height="10" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
</StackPanel>
</DataGridTextColumn.Header>
...
The second tabItem is defined like the first one, but it seems that the Binding DataContext.ShowFilterCommand is not reached. I tried to enter with debug there but is not reached.
Here is the method:
private void ShowFilterCommandRaised(object obj)
{
IsFilterOpen = !IsFilterOpen;
str = obj;
if (IsFilterOpen)
{
if (str.Equals("buttonClassViewClassFilter"))
{
FilterItems.Clear();
foreach (var classView in classViewItems)
{
FilterItems.Add(new CheckedListItem<string>(classView.ClassName, true));
}
}
if (str.Equals("buttonClassViewExtendsFilter"))
{
FilterItems.Clear();
foreach (var classView in classViewItems)
{
FilterItems.Add(new CheckedListItem<string>(classView.Category, true));
}
}
if (str.Equals("buttonFieldViewClassFilter"))
{
FilterItems.Clear();
foreach (var fieldView in fieldViewItems)
{
FilterItems.Add(new CheckedListItem<string>(fieldView.ClassName, true));
}
}
}
What am i doing wrong?
If you swap the order of the two TabItems, or set SelectedIndex="1" on the TabControl, you'll find that the one that's initially visible is always the only one that works. I added PresentationTraceSources.TraceLevel=High to the Command binding, and found that the binding in the TabItem that's hidden on startup tries to resolve its source property initially, and doesn't try again when that TabItem becomes active.
The trouble is that at the time of that first attempt at resolving the binding in the hidden tab item, none of the UI for that TabItem actually exists yet. Due to virtualization, it won't be created until it's needed. All that's created is its Header content, hanging in space. The DataGrid doesn't exist yet, so the AncestorType search never finds it. When the DataGrid is finally created, it seems there is no event that's raised to notify the Binding that it needs to repeat the ancestor search.
The fix for this is easy: Create the header content via a DataTemplate. That's the correct way to do it anyhow. The DataTemplate will be instantiated when the DataGrid is shown.
We'll use a value converter to create an identifier which tells the command what grid and column the user clicked. Notice that we're now giving each column a plain string for its Header property, and the TextBlock in the template changes to <TextBlock Text="{Binding}" />.
XAML
<TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
<TabControl.Resources>
<local:GetColumnIdentifier x:Key="GetColumnIdentifier" />
<DataTemplate x:Key="FilterColumnHeaderTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<Button
Margin="10,0,0,0"
Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding Converter={StaticResource GetColumnIdentifier}, RelativeSource={RelativeSource Self}}"
>
<Button.ContentTemplate>
<DataTemplate>
<Image Source="/Images/filter.png" Width="10" Height="10" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
</StackPanel>
</DataTemplate>
</TabControl.Resources>
<TabItem Header="Class">
<DataGrid
x:Name="ClassViewDataGrid"
ItemsSource="{Binding FilteredClassViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True"
>
<DataGrid.Columns>
<DataGridTextColumn
Header="Class"
Binding="{Binding ClassName}"
HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}"
/>
</DataGrid.Columns>
</DataGrid>
</TabItem>
<TabItem Header="Field">
<DataGrid
x:Name="FielsdViewDataGrid"
ItemsSource="{Binding FilteredFieldViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True"
>
<DataGrid.Columns>
<DataGridTextColumn
Header="Class"
Binding="{Binding ClassName}"
HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}"
/>
</DataGrid.Columns>
</DataGrid>
</TabItem>
</TabControl>
Value converter:
//using System.Windows.Markup.Primitives;
//using System.Windows.Controls.Primitives;
public class GetColumnIdentifier : IValueConverter
{
private static T GetVisualAncestor<T>(DependencyObject obj)
where T : DependencyObject
{
while (obj != null)
{
if (obj is T)
return obj as T;
else
obj = VisualTreeHelper.GetParent(obj);
}
return null;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Not all DataGridColumn subclasses have a Binding property.
var header = GetVisualAncestor<DataGridColumnHeader>((DependencyObject)value);
var datagrid = GetVisualAncestor<DataGrid>(header);
if (header?.Column != null)
{
MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(header.Column);
var bindingProp = markupObject.Properties.FirstOrDefault(p => p.Name == "Binding");
if (bindingProp?.Value is Binding binding)
{
return $"{datagrid?.Name}.{binding.Path.Path}";
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Here's another solution if you have multiple columns bound to the same path, and you need to distinguish among them (in that case though, you could use the above solution for most of them, but slip in a customized template for the odd special case):
<TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
<TabItem Header="Class">
<DataGrid
x:Name="ClassViewDataGrid"
ItemsSource="{Binding FilteredClassViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True"
>
<DataGrid.Columns>
<DataGridTextColumn
Header="Class"
Binding="{Binding ClassName}"
>
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<Button
Name="buttonClassViewClassFilter"
Margin="10,0,0,0"
Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}"
>
<Button.ContentTemplate>
<DataTemplate>
<Image Source="/Images/filter.png" Width="10" Height="10" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</TabItem>
<TabItem Header="Field">
<DataGrid
x:Name="FielsdViewDataGrid"
ItemsSource="{Binding FilteredFieldViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True"
>
<DataGrid.Columns>
<DataGridTextColumn
Header="Class"
Binding="{Binding ClassName}"
>
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<Button
Name="buttonFieldViewClassFilter"
Margin="10,0,0,0"
Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding Name, RelativeSource={RelativeSource Self}}"
>
<Button.ContentTemplate>
<DataTemplate>
<Image Source="/Images/filter.png" Width="10" Height="10" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</TabItem>
</TabControl>
Original Version
It turns out that OP has multiple filtered columns per grid, so the solution below won't work: The command needs to know not just which grid, but which column in the grid. DataGridColumn isn't in the visual tree so we can't use that x:Name for the command parameter. We could use {RelativeSource AncestorType=DataGridColumnHeader} and write a converter that returns DataGridColumnHeader.Column.Binding.Path.Path -- but both grids have columns named ClassName. Next up is a multibinding that passes that ancestor, and also the grid itself. Since OP's original solution involved distinct content per column header anyway, I decided to do it the easy but verbose way, with multiple templates.
I made one important change that will affect your code: Since the header content for both DataGrid columns is now being created by the same template, the name of the button is now the same for both. Therefore, CommandParameter is now bound to the name of the DataGrid.
<TabControl HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="716" Margin="10,0,0,0">
<TabControl.Resources>
<DataTemplate x:Key="FilterColumnHeaderTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<Button
Name="buttonClassFilter"
Margin="10,0,0,0"
Command="{Binding DataContext.ShowFilterCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding Name, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
>
<Button.ContentTemplate>
<DataTemplate>
<Rectangle Fill="DeepSkyBlue" Width="10" Height="10" />
</DataTemplate>
</Button.ContentTemplate>
</Button>
</StackPanel>
</DataTemplate>
</TabControl.Resources>
<TabItem Header="Class">
<DataGrid
x:Name="ClassViewDataGrid"
ItemsSource="{Binding FilteredClassViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True"
>
<DataGrid.Columns>
<DataGridTextColumn
Header="Class"
Binding="{Binding ClassName}"
HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}"
/>
</DataGrid.Columns>
</DataGrid>
</TabItem>
<TabItem Header="Field">
<DataGrid
x:Name="FielsdViewDataGrid"
ItemsSource="{Binding FilteredFieldViewItems}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True"
>
<DataGrid.Columns>
<DataGridTextColumn
Header="Class"
Binding="{Binding ClassName}"
HeaderTemplate="{StaticResource FilterColumnHeaderTemplate}"
/>
</DataGrid.Columns>
</DataGrid>
</TabItem>
</TabControl>
If you want to vary the header content between the columns in the two different DataGrids, you can do that with bindings or create a second template if necessary.
You could have also done this with a BindingProxy created in TabControl.Resources, but binding proxies are a last-ditch kludge that we use when there's no "correct" way to do something. In this case, the "correct" way is easy and direct and perfectly satisfactory.

StackPanel in a DataGrid doesn't collapse when it should

I have a problem with a StackPanel and its visibility in a DatagridCellTemplateColumn.
My ControlTemplate looks like this:
<ControlTemplate x:Key="PartPrioritySettingsGridCellTemplate">
<StackPanel Name="CellGrid" Orientation="Horizontal" Tag="{TemplateBinding Tag}"
Visibility="{Binding RelativeSource={RelativeSource Self},
Path=Tag.IsNotEmpty, Converter={StaticResource BoolToVisibility}}">
<CheckBox Margin="4,1,2,1"
IsChecked="{Binding Path=Tag.Items.IsChecked, ElementName=CellGrid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<xceed:IntegerUpDown Margin="2,1" Maximum="99" Minimum="1"
Value="{Binding Path=Tag.Priority, ElementName=CellGrid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button Margin="2,1,4,1" Command="{Binding Path=Tag.ShowDetailCommand, ElementName=CellGrid}"
Content="{Binding Path=Tag.ItemsCountString, ElementName=CellGrid}"
ContentStringFormat="{}{0:}" />
</StackPanel>
</ControlTemplate>
Usage of this template looks like this:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Width="auto" Tag="{Binding Webs}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
I want to make a DataGrid where the width of all columns is set to the width of the current content. But when the content of a column is collapsed, then the width of a column should be given only by the width of the header. Actually I don't know what is the problem in my solution, but all my columns have the same width, even if their content is collapsed.
What I'm trying to achieve looks like this:
What I'm getting looks like this:
And this is code of the DataGrid
<DataGrid Grid.Row="0"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserResizeRows="False"
ItemsSource="{Binding JobBomPriorityRows,
UpdateSourceTrigger=PropertyChanged}">
<!-- -->
<DataGrid.Resources>
<vc:BoolToVisibilityConverter x:Key="BoolToVisibility" />
<ControlTemplate x:Key="PartPrioritySettingsGridCellTemplate" TargetType="Control">
<StackPanel Name="CellGrid"
Width="auto"
Orientation="Horizontal"
Tag="{TemplateBinding Tag}"
Visibility="{Binding RelativeSource={RelativeSource Self},
Path=Tag.IsNotEmpty,
Converter={StaticResource BoolToVisibility}}">
<CheckBox Margin="4,1,2,1" IsChecked="{Binding Path=Tag.Items.IsChecked, ElementName=CellGrid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<xceed:IntegerUpDown Margin="2,1"
Maximum="99"
Minimum="1"
Value="{Binding Path=Tag.Priority,
ElementName=CellGrid,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
<Button Margin="2,1,4,1"
Command="{Binding Path=Tag.ShowDetailCommand,
ElementName=CellGrid}"
Content="{Binding Path=Tag.ItemsCountString,
ElementName=CellGrid}"
ContentStringFormat="{}{0:}"
Padding="3,0" />
</StackPanel>
</ControlTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Width="*"
Binding="{Binding Week}"
Header="Week"
IsReadOnly="True"
SortDirection="Ascending" />
<DataGridTextColumn Width="*"
Binding="{Binding JobBom}"
Header="Job Bom"
IsReadOnly="True" />
<DataGridTemplateColumn Width="auto"
Header="Web"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Tag="{Binding Webs}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="auto"
Header="Flange"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Tag="{Binding Flanges}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="auto"
Header="Plate"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Tag="{Binding Plates}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="auto"
Header="Gusset"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Tag="{Binding Gussets}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="auto"
Header="SP"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Tag="{Binding SPs}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="auto"
Header="STD G"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Tag="{Binding STD_Gs}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="auto"
Header="STD SP"
IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Control Tag="{Binding STD_SPs}" Template="{StaticResource PartPrioritySettingsGridCellTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>

Bind datagrid column visibility to a dictionary value

people! I have an issue:
i have an app on MVVM Light with DataGrid:
<DataGrid ItemsSource="{Binding Path=MyCollection, Mode=TwoWay}" AutoGenerateColumns="False" CanUserAddRows="False"
FontSize="14" Name="ItemGrid" SelectionUnit="FullRow" ColumnHeaderStyle="{StaticResource ResourceKey=DataGridColumnHeader}" Background="Transparent"
Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="4"
CanUserResizeRows="False" SelectionMode="Single" BorderThickness="0">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid
IsReadOnly="True"
AutoGenerateColumns="False"
ItemsSource="{Binding MyItems}"
SelectionUnit="FullRow"
Visibility="{Binding Path=DataContext.RowDetailsVisibility, Mode=TwoWay,Converter={StaticResource BoolToVisibilityConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
CanUserResizeRows="False"
CanUserResizeColumns="True"
SelectedItem="{Binding Path=DataContext.SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Visibility="Collapsed" Binding="{Binding ID}" Width="Auto" CellStyle="{StaticResource ResourceKey=DataGridCell}" />
<DataGridTextColumn Header="Title" Visibility="Visible" Binding="{Binding Title}" Width="Auto" CellStyle="{StaticResource ResourceKey=DataGridCell}" />
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Item Pack ID" Width="*" CellStyle="{StaticResource ResourceKey=DataGridCell}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Id, Mode=TwoWay}" Style="{StaticResource ResourceKey=TextBoxStyle}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Number" Width="*" CellStyle="{StaticResource ResourceKey=DataGridCell}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Number, Mode=TwoWay}" Style="{StaticResource ResourceKey=TextBoxStyle}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid.Columns>
<DataGrid.ContextMenu>
<ContextMenu Name="contextMenu" Style="{StaticResource ContextStyle}">
</MenuItem>
<MenuItem Header="Packs Columns"
ItemsSource="{Binding PacksCollection}"
DisplayMemberPath="Key"
Command="{Binding Path=DataContext.PacksCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
>
</MenuItem>
<MenuItem Header="Items Columns"
Command="{Binding Path=DataContext.ItemsCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
ItemsSource="{Binding ItemsCollection}" DisplayMemberPath="Key">
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
So, if you understand, i have a grid with Packs(Id,Number),each Pack have some Items(Id,Title). I want to have a context menu, which have 2 lists: Packs and Items. In each menu item we can choose what column to show.
ItemsCollection and PacksCollection are Dictionary where String - Column Header(same as in data grid) and bool - visibility state(true for Visible, false for Collapsed).
Question: how to bind MVVM click on menu item, that will change column visibility. I tried some solutions, but they don't worked for me.
I need to change visibility for DataGrid columns(Id,Number) and for RowDetails DataGrid - Id, Title. Help please, i don't think this is so hard.
Thank you.

WPF DataGrid row height

I have a datagrid in a WPF project. I've set the columns width to be have maximum limits,
and I want the data to likewise be stretched to fit in the rows. But that doesn't happen.... The contents just stays the same size and the cell is cutoff. Any ideas?
Here is the code :
<DockPanel>
<DataGrid x:Name="nirGrid" x:Uid="nirGrid" AutoGenerateColumns="False" AlternationCount="2" SelectionMode="Single" DockPanel.Dock="Top" Margin="10,50,10,50" FlowDirection="RightToLeft" ColumnWidth="SizeToCells" CanUserSortColumns="False" CanUserResizeColumns="False" CanUserReorderColumns="False" GridLinesVisibility="None" HeadersVisibility="None" SelectionUnit="Cell" VerticalAlignment="Stretch" EnableRowVirtualization="False" IsReadOnly="True" RowDetailsVisibilityMode="Visible" MinRowHeight="0" CanUserResizeRows="True" RowHeaderWidth="0">
<DataGrid.Style>
<Style>
<Setter Property="ScrollViewer.CanContentScroll" Value="False" />
</Style>
</DataGrid.Style>
<DataGrid.Columns >
<DataGridTextColumn Binding="{Binding Path=task_desc}" IsReadOnly="True" Header="test1" Width="SizeToCells" MaxWidth="330" >
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Path=task_req_date}" IsReadOnly="True" Header="test2" Width="SizeToCells" MaxWidth="70" >
</DataGridTextColumn>
<DataGridTemplateColumn Header="delete" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="delete" ToolTip="delete" Opacity="0.8" Click="Button_Click" MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Source="/exhibits;component/Images/exit1.png" Width="15" Height="15" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Try using the TextBlock. It should automatically wrap the content to your desired size.
<DataGridTemplateColumn Width="*" Header="Column 2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=task_req_date}" TextWrapping="Wrap" AcceptsReturn="true" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Categories

Resources