问题
How can I implement in richTextBox
something like filter (connected e.g. with combobox
) that'll be responsible for showing only lines containing selected word (filters)?
I'm not talking about removing other lines - only "hide".
Is it possible?
Eventually I could use another type control, but if it's not neccessary I'd like to use richTextBox.
I thought now, about storing data in some structure, and make filtering based on this used structure. But don't know if it's efficient solution.
回答1:
Try to make something like this
public string[] RtbFullText;
private void button7_Click(object sender, EventArgs e)
{
RtbFullText = richTextBox1.Text.Split('\n');
}
private void button8_Click(object sender, EventArgs e)
{
//Filter
richTextBox1.Text = "";
foreach (string _s in RtbFullText)
{
if (_s.Contains("Filter"))
richTextBox1.Text += _s + "\n";
}
}
回答2:
So you can do this
public class NewRichTextBox : RichTextBox
{
public string[] TotalText;
private bool filter = false;
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
if (!filter)
TotalText = Text.Split('\n');
}
public void Filter(string sf)
{
filter = true;
Text = "";
foreach (string _s in TotalText)
{
if (_s.Contains(sf))
Text += _s + "\n";
}
filter = false;
}
}
public Form1()
{
InitializeComponent();
NewRichTextBox myrtb = new NewRichTextBox();
myrtb.Name = "NRTB";
Controls.Add(myrtb);
}
private void button1_Click(object sender, EventArgs e)
{
NewRichTextBox mtrb = (NewRichTextBox)Controls.Find("NRTB", false)[0];
mtrb.Filter("Filter");
}
回答3:
OMG i do it, use this class:
public class ListWithRTB : IList
{
private List<string> _contents = new List<string>();
private int _count;
string lastsearch = "";
public ListWithRTB()
{
_count = 0;
}
public object rtb;
private void UpdateRtb(string search)
{
lastsearch = search;
if (rtb is RichTextBox)
{
((RichTextBox)rtb).Text = "";
List<string> help_contents;
if (search != "")
help_contents = _contents.Where(s => s.Contains(search)).ToList();
else
help_contents = _contents;
for (int i = 0; i < help_contents.Count; i++)
{
((RichTextBox)rtb).Text += help_contents[i] + "\n";
}
}
}
public void Filter(string search)
{
UpdateRtb(search);
}
public int Add(object value)
{
if (_count < _contents.Count + 1)
{
_contents.Add((string)value);
_count++;
UpdateRtb(lastsearch);
return (_count);
}
else
{
return -1;
}
}
public void RemoveAt(int index)
{
_contents.RemoveAt(index);
_count--;
UpdateRtb(lastsearch);
}
public void Clear()
{
_contents.Clear();
UpdateRtb(lastsearch);
_count = 0;
}
public bool Contains(object value)
{
return _contents.Contains((string)value);
}
public int IndexOf(object value)
{
return _contents.IndexOf((string)value);
}
public void Insert(int index, object value)
{
_contents.Insert(index,(string) value);
_count++;
}
public bool IsFixedSize
{
get
{
return false;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public void Remove(object value)
{
RemoveAt(IndexOf(value));
}
public object this[int index]
{
get
{
return _contents[index];
}
set
{
_contents[index] = value.ToString();
}
}
public void CopyTo(Array array, int index)
{
int j = index;
for (int i = 0; i < Count; i++)
{
array.SetValue(_contents[i], j);
j++;
}
}
public int Count
{
get
{
return _count;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return this;
}
}
public IEnumerator GetEnumerator()
{
throw new Exception("The method or operation is not implemented.");
}
public void PrintContents()
{
Console.WriteLine("List has a capacity of {0} and currently has {1} elements.", _contents.Count, _count);
Console.Write("List contents:");
for (int i = 0; i < Count; i++)
{
Console.Write(" {0}", _contents[i]);
}
Console.WriteLine();
}
}
And this how you can use it
ListWithRTB _mlrtb = new ListWithRTB();
private void button1_Click(object sender, EventArgs e)
{
_mlrtb.rtb = richTextBox1;
_mlrtb.Add("Filter");
_mlrtb.Add("123");
_mlrtb.Add("111 Filter");
}
private void button2_Click(object sender, EventArgs e)
{
_mlrtb.Filter("Filter");
}
private void button3_Click(object sender, EventArgs e)
{
_mlrtb.Filter("");
}
回答4:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrEmpty(SearchableString) && !string.IsNullOrEmpty(FullRichtxt))
{
var SplitedTxt = FullRichtxt.Split('\n').ToList<string>();
List<string> filterlist = SplitedTxt.Where(x => x.Contains(contx.SearchableString)).ToList<string>();
string FilterString=string.Empty;
foreach(string str in filterlist)
{
FilterString+=str+"\n";
}
(RichTextBox1 as RichTextBox).AppendText(FilterString);
}
}
回答5:
I know this has been a very old question however I ran into the same issue and implemented it which also retains any RTF formatting.
/// <summary>
/// This Control allows to filter the content of the RichTextBox by either manually
/// calling <c>ApplyFilter(string)</c> with the search string or specifying a TextBox Control
/// as a filter reference.
///
/// Matching lines will be retained, other will be deleted.
///
/// Retains RTF formatting and when removing the filter restores the original content.
///
/// Ideal for a Debug Console.
///
/// </summary>
public class RichFilterableTextBox : RichTextBox
{
private Timer timer;
private string OriginalRTF = null;
private TextBox _filterReference;
private int _interval = 2000;
public TextBox FilterReference
{
get => _filterReference;
set
{
//if we had already a filter reference
if (_filterReference != null)
{
//we should remove the event
_filterReference.TextChanged -= FilterChanged;
}
_filterReference = value;
//if our new filter reference is not null we need to register our event
if (_filterReference != null)
_filterReference.TextChanged += FilterChanged;
}
}
/// <summary>
/// After the filter has been entered into the FilerReference TextBox
/// this will auto apply the filter once the interval has been passed.
/// </summary>
public int Interval
{
get => _interval;
set
{
_interval = value;
timer.Interval = Interval;
}
}
public RichFilterableTextBox()
{
timer = new Timer();
timer.Interval = Interval;
timer.Tick += TimerIntervalTrigger;
}
public void SetFilterControl(TextBox textbox)
{
this.FilterReference = textbox;
}
public void ApplyFilter(string searchstring)
{
int startIndex = 0;
int offset = 0;
//check each line
foreach (var line in this.Lines)
{
offset = 0;
SelectionStart = startIndex + offset;
SelectionLength = line.Length + 1;
//if our line contains our search string/filter
if (line.Contains(searchstring))
{
//we apply an offset based on the line length
offset = line.Length;
}
else
{
//otherwise delete the line
SelectedText = "";
}
//move the start index forward based on the current selected text
startIndex += this.SelectedText.Length;
}
}
private void FilterChanged(object sender, EventArgs e)
{
//take snapshot of original
if (OriginalRTF == null)
{
OriginalRTF = this.Rtf;
}
else
{
//restore original
Rtf = OriginalRTF;
OriginalRTF = null;
}
timer.Stop();
timer.Start();
}
private void TimerIntervalTrigger(object sender, EventArgs e)
{
//stop the timer to avoid multiple triggers
timer.Stop();
//apply the filter
ApplyFilter(FilterReference.Text);
}
protected override void Dispose(bool disposing)
{
timer.Stop();
timer.Dispose();
base.Dispose(disposing);
}
}
This control can be either used standalone and be filter by calling the method
ApplyFilter(string searchString)
with the desired search string. Or it can be connected to a TextBox
where you will be able to enter the phrase in. After a set timer interval it will auto trigger the filtering.
I am using this as a Log Display during runtime where I am also applying color codes to severity and my goal was to retain the formatting as well as be able to quickly search/filter. I attached a few screenshots:
There is still room for improvements and I hope this can be used as a starting code base.
来源:https://stackoverflow.com/questions/10188933/richtextbox-with-text-filtering