简体   繁体   中英

Making specific part of Text bold in RichTextBox in a DataGrid using WPF

I'm making a C# WPF application and currently have a DataGrid that contains various elements including a RichTextBox so that users can edit the text. However I would like to also give the option of making specific parts of the Text contained in the RichTextBox bold. This should be done by selecting part of the Text in a TextBox and pressing a button, that would make the selected text bold.

So the highlighted "Lorem ipsum dolor sit amet" would be made bold when the button is pressed.

My XAML is setup like this:

<DataGrid Grid.Row="1" AutoGenerateColumns="False" Name="DescriptionGrid"
      RowHeaderWidth="15"
      ItemsSource="{Binding Descriptions}"
      VirtualizingPanel.IsVirtualizing="False">
<DataGrid.Columns>
    <DataGridTemplateColumn Header="Description" Width="300">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <RichTextBox Width="Auto" AcceptsReturn="True">
                    <FlowDocument>
                        <Paragraph>
                            <Run Text="{Binding desc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        </Paragraph>
                    </FlowDocument>
                </RichTextBox>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid.Columns>

I have not included every column, but it should give a understanding of what I'm working with.

So far I've managed to get the highlighted text. I then tried to add various bold tags around the selected text, however these tags just show up in the textbox.

However I would like to also give the option of making specific parts of the Text contained in the RichTextBox bold. This should be done by selecting part of the Text in a TextBox and pressing a button, that would make the selected text bold

There are a few ways this can be accomplished. Currently it appears you are following mvvm with binding, this is the preferred way when working with wpf . With this in mind, you could create a new class that inherits the RichTextBox and implement the behavior you are needing.

Here's an example class that does just what you need:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace ChangeFontSelectionGridWPF
{
    public class RichTextSelection : RichTextBox
    {
        public static readonly DependencyProperty DoBoldSelectionProperty = DependencyProperty.Register(
                                                                                                    "DoBoldSelection", typeof(bool),
                                                                                                    typeof(RichTextSelection),
                                                                                                    new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnBoldSelectionChanged))
                                                                                                    );

        public bool DoBoldSelection
        {
            get => (bool)GetValue(DoBoldSelectionProperty);
            set => SetValue(DoBoldSelectionProperty, value);
        }

        public RichTextSelection()
            : base()
        {
        }

        private static void OnBoldSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RichTextSelection rchTextSel = (RichTextSelection)d;
            if (rchTextSel.Selection != null)
                rchTextSel.Selection.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
        }
    }
}

After you recompile, you then can add this as your DataTemplate for that column, something like:

<DataTemplate>
             <local:RichTextSelection Width="Auto"
                 AcceptsReturn="True"
                 DoBoldSelection="{Binding AllowBoldHighlight}"
                                                     >
                                <FlowDocument>
                                    <Paragraph>
                                        <Run Text="{Binding desc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                                    </Paragraph>
                                </FlowDocument>
                            </local:RichTextSelection>
                        </DataTemplate>

You'll notice a dependency property: DoBoldSelection . This property handles changing the font weight of the selected text. In the example above, that property is bound to a property in my List<DescriptionObject> which is AllowBoldHighlight .

My DescriptionObject class looks like:

public class DescriptionObject : INotifyPropertyChanged
    {
        public string desc { get; set; } = string.Empty;

        private bool allowHighlight = false;
        public bool AllowBoldHighlight
        {
            get => allowHighlight;
            set => SetProperty(ref allowHighlight, value);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propName = "")
        {
            if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
            storage = value;
            OnPropertyChanged(propName);
            return true;
        }

    }

MainWindow.xaml looks like:

<Window x:Class="ChangeFontSelectionGridWPF.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:local="clr-namespace:ChangeFontSelectionGridWPF"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        Width="800"
        Height="450"
        mc:Ignorable="d"
        >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0"
                Grid.Column="1"
                Margin="10"
                Click="Button_Click"
                Content="Bold"
                />
        <DataGrid x:Name="DescriptionGrid"
                  Grid.Row="1"
                  Grid.ColumnSpan="2"
                  AutoGenerateColumns="False"
                  ItemsSource="{Binding Descriptions}"
                  >
            <DataGrid.Columns>
                <DataGridTemplateColumn Width="300" Header="Description">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <local:RichTextSelection Width="Auto"
                                                     AcceptsReturn="True"
                                                     DoBoldSelection="{Binding AllowBoldHighlight}"
                                                     >
                                <FlowDocument>
                                    <Paragraph>
                                        <Run Text="{Binding desc, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                                    </Paragraph>
                                </FlowDocument>
                            </local:RichTextSelection>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>

    </Grid>
</Window>

MainWindow.cs looks like:

public partial class MainWindow : Window
    {
        public List<DescriptionObject> Descriptions { get; set; } = new List<DescriptionObject>();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            Descriptions.Add(new DescriptionObject() { desc = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?" });
            Descriptions.Add(new DescriptionObject() { desc = "rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?" });
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (DescriptionGrid.SelectedItem is DescriptionObject dobj)
            {
                dobj.AllowBoldHighlight = true;
                dobj.AllowBoldHighlight = false;
            }
        }

    }

You'll notice that in Button_Click is where you could handle changing the FontWeight of selected text; basic example. The main driver for this is dobj.AllowBoldHighlight = true . What's happening is when you select/highlight text and then click on the button, dobj.AllowBoldHighlight property get's change which the fires off the OnBoldSelectionChanged in the RichTextSelection class. The example above gives you flexibility to turn it off and on per object/instance in your grid.

Here's a short clip of it working:

在此处输入图像描述

Hopefully this helps and addresses your concern, if any issues please let me know.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM