Gistiv
Gistiv

Reputation: 167

WPF - Change the color of an entire textblock line

In my WPF Application I have a two textblocks which get filled from the code behind with a run. Every second line should have a different background color so it gets easier to read. Unfortunately, the lines are only dyed as far as they are written. But I want the background color to go over the entire line and not just the written area.

Code:

         for (int i = 0; i < GlobalSettings.prefixList.Count; i++)
         {
            runLeft = new Run(GlobalSettings.prefixList[i].prefix + "\n");
            runRight = new Run(GlobalSettings.prefixList[i].amount + "\n");
            
            if (i % 2 == 0)
            {
                runLeft.Background = Brushes.Gray;
                runRight.Background = Brushes.Gray;
            }
            else
            {
                runLeft.Background = Brushes.LightGray;
                runRight.Background = Brushes.LightGray;
            }

            tblock_StatisticsLeft.Inlines.Add(runLeft);
            tblock_StatisticsRight.Inlines.Add(runRight);
         }

Example Picture

The two textblocks are seamlessly together in the middle so it would look like it is a single line in a single textblock. The spaces between the lines are negligible if this makes it easier.

Is there a solution without using a textbox or richtextbox?

EDIT:

XAML Code:

<UserControl x:Class="MuseKeyGenApp.UCStartUp"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:MuseKeyGenApp"
         mc:Ignorable="d"   
         Background = "#FF0069B4"
         d:DesignHeight="500" d:DesignWidth="800">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="26"/>
        <RowDefinition Height="0"/>
        <RowDefinition Height="*" MinHeight="80"/>
        <RowDefinition Height="*" MinHeight="80"/>
        <RowDefinition Height="*" MinHeight="80"/>
        <RowDefinition Height="*" MinHeight="80"/>
        <RowDefinition Height="*" MinHeight="80"/>
        <RowDefinition Height="0"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" MinWidth="150"/>
        <ColumnDefinition Width="0.75*" MinWidth="100"/>
        <ColumnDefinition Width="0.75*" MinWidth="100"/>
        <ColumnDefinition Width="0.75*" MinWidth="100"/>
        <ColumnDefinition Width="0.75*" MinWidth="100"/>
    </Grid.ColumnDefinitions>


    <ScrollViewer Grid.Row="2" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="10,35,12,12" Name="sv_PrefixList">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" x:Name="tblock_StatisticsLeft" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,0,0" Text="TextBlock" VerticalAlignment="Stretch" TextAlignment="Left"/>
            <TextBlock Grid.Column="1" x:Name="tblock_StatisticsRight" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,10,0" Text="TextBlock" VerticalAlignment="Stretch" TextAlignment="Right"/>
        </Grid>
    </ScrollViewer>

</Grid>

I left out all the other stuff of the control that is not relevant.

Upvotes: 1

Views: 1519

Answers (2)

rmojab63
rmojab63

Reputation: 3629

Here is the correct way of doing this:

Xaml:

 <Window.Resources>
    <local:BackConverter x:Key="BackConverter"/>
</Window.Resources>
<Grid Margin="10">
    <ItemsControl Name="ic"> 
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DockPanel LastChildFill="False">
               <DockPanel.Background>
                            <MultiBinding Converter="{StaticResource BackConverter}">
                                <Binding />
                                <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}"/>
                            </MultiBinding>
                        </DockPanel.Background>
                    <TextBlock DockPanel.Dock="Left" Text="{Binding Left}">
                    </TextBlock>
                    <TextBlock DockPanel.Dock="Right" Text="{Binding Right}">
                    </TextBlock>
                </DockPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

c# code:

  public class obj
    {
        public string Left { get; set; }
        public string Right { get; set; }
    }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        List<obj> objects = new List<obj>();
        for (int i = 0; i < 10; i++)
        {
            var left = "aaaaa";
            var right = "bbbbb";
            objects.Add(new obj() { Left = left, Right = right }); 
        }
        ic.ItemsSource = objects;

    }

the converter:

public class BackConverter : IMultiValueConverter
{

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var index = ((ItemsControl)values[1]).Items.IndexOf(values[0]);
        if (index % 2 == 0)
            return Brushes.Gray;
        return Brushes.White; 
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    } 
}

Upvotes: 0

mm8
mm8

Reputation: 169390

You could (should) use an ItemsControl. Set the ItemsSource property of it to your GlobalSettings.prefixList collection, i.e. you replace your for loop with this:

ic.ItemsSource = GlobalSettings.prefixList;

Make sure that "prefix" and "amount" are public properties (and not fields) of your "prefix" type or whatever you call it:

public string prefix { get; set; }

You then put the Grid with the TextBlocks in the ItemTemplate of the ItemsControl and bind the TextBlocks to the "prefix" and "amount" properties:

<ScrollViewer Grid.Row="2" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="10,35,12,12" Name="sv_PrefixList">
    <ItemsControl x:Name="ic" AlternationCount="2">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="grid">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" x:Name="tblock_StatisticsLeft" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,0,0" VerticalAlignment="Stretch" TextAlignment="Left"
                                       Text="{Binding prefix}"/>
                    <TextBlock Grid.Column="1" x:Name="tblock_StatisticsRight" HorizontalAlignment="Stretch" LineHeight="20" TextWrapping="Wrap" Margin="0,0,10,0" VerticalAlignment="Stretch" TextAlignment="Right"
                                       Text="{Binding amount}"/>
                </Grid>
                <DataTemplate.Triggers>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="Gray" TargetName="grid"/>
                    </Trigger>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGray" TargetName="grid"/>
                    </Trigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

This should get you coloured lines.

Upvotes: 1

Related Questions