Home > Software design >  Change the font weight of specific cells in WPF
Change the font weight of specific cells in WPF

Time:03-26

I'm trying to make a grid that stores Dates and if the date is less than 4 days away then the date becomes bold , i know the column and the row of the cell , but i can't figure out how to change the property font weight of THOSE specific cells. Is there a way you could do that from the code behind preferably?

XAML:

<DataGrid Name="offers_grid" Style="{StaticResource Offers_data_grid}">
     <DataGrid.Resources>
         <Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource Transparent_cell}" />
         <Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource Transparent_header_column}"/>
     </DataGrid.Resources>
                 <DataGrid.Columns>

                        <DataGridTextColumn Header="ID" Binding="{Binding id}" Width="0.3*" />
                        <DataGridTextColumn Header="Account" Binding="{Binding account.name}" Width="1*" />
                        <DataGridTextColumn Header="Price"
                                            Binding="{Binding price, Converter={StaticResource PriceConverter}}"
                                            Width="1*" />
                        <DataGridTextColumn Header="Best Before"
                                            Binding="{Binding best_before ,Converter={StaticResource DateTimeConverter}}"
                                            Width="1*" />
                        <DataGridTextColumn Header="Auditor"
                                            Binding="{Binding assigned_to , Converter={StaticResource AuditorConverter}}"
                                            Width="1*" />
                    </DataGrid.Columns>
</DataGrid>

Converter to make a date into a string so it can be inserted into a cell of the datagrid with the correct date format:

public class DateTimeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var v = value as DateTime?;
            if (v == null)
                return "No Date assigned";

            return v.Value.ToString("d MMMM yyyy");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

CodePudding user response:

It seems you need a converter.

  • Add a repository named "Converters" to your project
  • Create a new class "DateToBoldConverter" like this :
[ValueConversion(typeof(DateTime), typeof(FontWeight))]
public sealed class DateToBoldConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is DateTime)) return null;
        // Assuming your dates are type of DateTime
        return (DateTime.Now - (DateTime)value).TotalDays < 4 ? FontWeights.Bold : FontWeights.Regular;
    }
    // You don't need to convert back
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
  • Add the converter to your xaml as ressource :

<Application.Ressources>
    <ResourceDictionary>
        <Converters:DateToBoldConverter x:Key="DateToBold"/>
    </ResourceDictionary>
</Application.Ressources>
  • In your xaml, in your control that display date add this (example with textblock) :
<TextBlock Text="{Binding [YourDateProperty]" FontWeight="Binding [YourDateProperty], Converter={StaticResource DateToBold}"/>

With that, the converter will return the good FontWeight according to the value of the date displayed.
Next time, please share your code, it will help to understand your problem and try to resolve it.
Sorry for my english, I'm a french developer.

[UPDATE]
I made test in a little project and it works. I have used a ListView instead of DataGrid to feel free to define my render as I want.

Model : Item.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApplication1.Models
{
    public class Item
    {
        public int Id;
        public DateTime BestBefore;
    }
}

ViewModel : ItemViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApplication1.Models;

namespace WpfApplication1.ViewModels
{
    public class ItemViewModel
    {
        private readonly Item _item;

        public int Id => _item.Id;
        public DateTime BestBefore => _item.BestBefore;
        public ItemViewModel(Item item)
        {
            _item = item;
        }
    }
}

ViewModel : ViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApplication1.Models;

namespace WpfApplication1.ViewModels
{
    public class ViewModel
    {
        public ObservableCollection<ItemViewModel> Items { get; set; }
        public ViewModel()
        {
            Items = new ObservableCollection<ItemViewModel>();

            // Here, you get your data. I will use a mock data collection
            Items.Add(new ItemViewModel(new Item()
            {
                Id = 1,
                BestBefore = DateTime.ParseExact("24/03/2022", "dd/MM/yyyy", CultureInfo.CurrentCulture)
            }));
            Items.Add(new ItemViewModel(new Item()
            {
                Id = 1,
                BestBefore = DateTime.ParseExact("10/03/2022", "dd/MM/yyyy", CultureInfo.CurrentCulture)
            }));

        }
    }
}

View : MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        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"
        xmlns:converters="clr-namespace:WpfApplication1.Converters"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <converters:DateToBoldConverter x:Key="DateToBold"/>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <ListView ItemsSource="{Binding Items}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="ID">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Id}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Best Before">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding BestBefore}" FontWeight="{Binding BestBefore, Converter={StaticResource DateToBold}}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

Result

Result

This is correct beacause the date in bold is less than 4 days from today

CodePudding user response:

NOTE: I'm marking this answer correct for the sole reason of using the DataGrid control, in your case it might be better to use a different control , but in my case i need to use the DataGrid Control and therefore this is the best answer i could find to the problem. If you know a better way to do it, please leave an answer

The only way i have found of changing the FontWeight of cells dynamically is adding a new bool property onto the item Class and making a new cell style with a datatrigger on that property

XAML:

     <Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource Transparent_cell}"
                               x:Key="Date_transparent_cell">
                            <d:Style.DataContext>
                                <local:OfferDataGridData />
                            </d:Style.DataContext>
                            <Style.Triggers>

                                <DataTrigger Binding="{Binding bold}" Value="True">
                                    <Setter Property="FontWeight" Value="Bold" />
                                    <Setter Property="Foreground" Value="GreenYellow" />
                                </DataTrigger>

                            </Style.Triggers>
                        </Style> 

Item Data Class:

public record OfferDataGridData
{
    public int      id          { get; set; }
    public Account  account     { get; set; } = null!;
    public decimal  price       { get; set; }
    public DateTime best_before { get; set; }
    public Auditor? assigned_to { get; set; }

    public bool bold { get; set; } = false;
}
  • Related