Home > Blockchain >  RichTextBox WPF limit content in one line
RichTextBox WPF limit content in one line

Time:11-18

I need to have parts of the string in bold. Since TextBlock does not support having parts of the text in bold, I moved to using RichTextBox. Now, I want my RichTextBox to limit to a single line and if the contents are longer to fit in single line, it should use character ellipsis to truncate the string. Following is my ViewModel bound to RichTextBox,

    public class SearchSuggestionViewModel : BindableBase, IComparable<SearchSuggestionViewModel>
    {
    private Suggestion _suggestion;
    private string m_DocumentXaml = string.Empty;


    public SearchSuggestionViewModel(Suggestion suggestion)
        {
        _suggestion = suggestion;
        if (string.IsNullOrEmpty(suggestion.Text))
            return;
        string searchText = _suggestion.Text;
        FlowDocument document = new FlowDocument();
        Paragraph paragraph = new Paragraph();
        Run run = new Run();

        while (searchText.Contains("<b>"))
            {
            string initialText = searchText.Substring(0, searchText.IndexOf("<b>"));
            run.Text = initialText;
            paragraph.Inlines.Add(run);
            searchText = searchText.Substring(searchText.IndexOf("<b>")   "<b>".Length);
            string boldText = searchText;
            if (searchText.Contains("</b>"))
                boldText = searchText.Substring(0, searchText.IndexOf("</b>"));
            run = new Run();
            run.FontWeight = FontWeights.Bold;
            run.Text = boldText;
            paragraph.Inlines.Add(run);

            searchText = searchText.Substring(searchText.IndexOf("</b>")   "</b>".Length);
            }
        run = new Run();
        run.Text = searchText;
        paragraph.Inlines.Add(run);
        document.Blocks.Add(paragraph);
        DocumentXaml = XamlWriter.Save(document);
        }

    public string Id
        {
        get
            {
            return _suggestion.Id;
            }
        }


    public string SearchSuggestionText
        {
        get
            {
            if (!string.IsNullOrWhiteSpace( _suggestion.Text))
                return _suggestion.Text.Replace("<b>", "").Replace("</b>", "");
            return string.Empty;
            }
        }



    /// <summary>
    /// The text from the FsRichTextBox, as a XAML markup string.
    /// </summary>
    public string DocumentXaml
        {
        get
            {
            return m_DocumentXaml;
            }

        set
            {
            SetProperty(ref m_DocumentXaml, value, nameof(DocumentXaml));
            }
        }


    public override int GetHashCode()
        {
        return base.GetHashCode();
        }

    public override bool Equals(object obj)
        {
        if (!(obj is SearchSuggestionViewModel))
            return false;
        SearchSuggestionViewModel otherTag = (SearchSuggestionViewModel)obj;
        if (SearchSuggestionText.Equals(otherTag.SearchSuggestionText))
            return true;
        return false;
        }

    public int CompareTo(SearchSuggestionViewModel compareSearchSuggestionViewModel)
        {
        // A null value means that this object is greater.
        if (compareSearchSuggestionViewModel == null)
            return 1;

        else
            return this.SearchSuggestionText.CompareTo(compareSearchSuggestionViewModel.SearchSuggestionText);
        }
    public override string ToString()
        {
        return _suggestion.Text;
        }
    }

Any suggestions on how can I achieve to have character ellipsis before the line end.

Regards, Umar

CodePudding user response:

You should be able to use a TextBlock with text wrapping and text trimming:

<TextBlock TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis">
    <Run>This text is</Run>
    <Run FontWeight="Bold" Text="partly bold"/>
    <Run>and wraps.</Run>
</TextBlock>

If you are creating the TextBlock programmatically, it has an Inlines property to which you can add the Run elements.

CodePudding user response:

With thanks to mm8, his answer gave me a direction. But I needed a solution to bind to a collection from the ViewModel. And the number of bold areas in string are decided at runtime. So, I have created a dependency property. And following worked for me. Sharing for benefit of others in future.

TextBlockExtensions.cs

public class TextBlockExtensions
{
    public static IEnumerable<Inline> GetBindableInlines(DependencyObject obj)
    {
        return (IEnumerable<Inline>)obj.GetValue(BindableInlinesProperty);
    }

    public static void SetBindableInlines(DependencyObject obj, IEnumerable<Inline> value)
    {
        obj.SetValue(BindableInlinesProperty, value);
    }

    public static readonly DependencyProperty BindableInlinesProperty =
        DependencyProperty.RegisterAttached("BindableInlines", typeof(IEnumerable<Inline>), typeof(TextBlockExtensions), new PropertyMetadata(null, OnBindableInlinesChanged));

    private static void OnBindableInlinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var Target = d as TextBlock;

        if (Target != null)
        {
            Target.Inlines.Clear();
            Target.Inlines.AddRange((System.Collections.IEnumerable)e.NewValue);
        }
    }
}

In my ViewModel, I added,

    private ObservableCollection<Inline> _searchSuggestionInlines;
    public ObservableCollection<Inline> SearchSuggestionInlines
    {
        get
        {
            return _searchSuggestionInlines;
        }
        set
        {
            SetProperty(ref _searchSuggestionInlines, value, nameof(SearchSuggestionInlines));
        }
    }

    //To populate the inlines
    public SearchSuggestionViewModel(Suggestion suggestion)
        {
        _suggestion = suggestion;
        if (string.IsNullOrEmpty(suggestion.Text))
            return;
        string searchText = _suggestion.Text;

        ObservableCollection<Inline> inlines = new ObservableCollection<Inline>();

        Run run = new();
        while (searchText.Contains("<b>"))
            {
            string initialText = searchText.Substring(0, searchText.IndexOf("<b>"));
            run.Text = initialText;
            inlines.Add(run);
            searchText = searchText.Substring(searchText.IndexOf("<b>")   "<b>".Length);
            string boldText = searchText;
            if (searchText.Contains("</b>"))
                boldText = searchText.Substring(0, searchText.IndexOf("</b>"));
            run = new Run
            {
                FontWeight = FontWeights.Bold,
                Text = boldText
            };
            inlines.Add(run);
            searchText = searchText.Substring(searchText.IndexOf("</b>")   "</b>".Length);
            }
        run = new Run
        {
            Text = searchText
        };
        inlines.Add(run);
        SearchSuggestionInlines = inlines;
        }

While the following was added to View,

<TextBlock controls:TextBlockExtensions.BindableInlines="{Binding Path=SearchSuggestionInlines, Mode=OneWay}" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" ToolTip="{Binding Path=SearchSuggestionText, Mode=OneWay}"/>

Regards,
Umar

  • Related