I'm using Caliburn Micro, and have a ListBox that is working to display a list of items I have bound to it from my ViewModel.
However, I am now looking into how to dynamically format each ListItem i.e. in my case, each string can have up to N values that are between two tokens, and I need these to be formatted to bold.
I'm able to parse the text into a list, and then mark which word or chunk of words need to be formatted and which do not, however I am not sure how to show this in my ListBox. From looking around, I see that some people recommend using a converter that would parse the text string?
My XAML at the moment for the listbox looks like - this was working when there was only a single keyword I needed to format, but have since found out there can be multiple occurrences in a single string so am unable to predict the structure anymore.
<ListBox ItemsSource="{Binding HighlightList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Path=mStartText}"/>
<Run Text="{Binding Path=mBoldText}"/>
<Run Text="{Binding Path=mEndText}"/>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Has anyone else been able to achieve something similar? Thanks in advance for any hints!
EDIT:
So, for further clarity lets say I have two strings:
String 1 - "This is a Test string"
String 2 - "This is is also a Test string
What I have to do is display the above strings in the ListBox with the strings that are wrapped in EM tags (Italics in the example above) to be bold and red font colour.
What I have done now is create a list of objects that will have two variables each - the string content, and string type (highlighted or not highlighted) and parse each string and break it down so that I mark which parts of it can be printed as is, and which need to be printed in the highlighted format.
ViewModel:
public ObservableCollection<HighlightItem> HighlightList
{
get
{
return _highlightList;
}
set
{
_highlightList = value;
NotifyOfPropertyChange(() => HighlightList);
}
}
public void ParseHighlights()
{
ObservableCollection<HighlightItem> hlList = new ObservableCollection<HighlightItem>();
string START_HL_TOKEN = "<em>";
string END_HL_TOKEN = "</em>";
if (_documentSnippets.Count > 0)
{
foreach (var hlItem in _documentSnippets.Snippets["text"])
{
// Remove tab characters
string temp = hlItem.Replace("\t", "");
// Remove multiple newline characters and replace with a single one
Regex regex = new Regex("(\\n){2,}");
string clean_temp = regex.Replace(temp, "\n");
string startText = "", hlText = "", endText = "";
int start_idx = 0;
int end_idx = 0;
List<string> stringTokenized = new List<string>();
// THIS BELOW IS PART OF MY NEW APPROACH
while(start_idx != clean_temp.Length)
{
end_idx = clean_temp.IndexOf(START_HL_TOKEN, start_idx);
// Highlight token is at the start
if(end_idx == 0)
{
start_idx = end_idx;
end_idx = clean_temp.IndexOf(END_HL_TOKEN, start_idx);
stringTokenized.Add(clean_temp.Substring(start_idx + 4, end_idx - start_idx));
// Move pointer to start of next section, keeping in mind the length of the END token
start_idx = end_idx + 4;
}
else if(end_idx == -1)
{
end_idx = clean_temp.Length;
stringTokenized.Add(clean_temp.Substring(start_idx, end_idx - start_idx));
start_idx = end_idx;
}
else
{
stringTokenized.Add(clean_temp.Substring(start_idx, end_idx - start_idx));
start_idx = end_idx;
end_idx = clean_temp.IndexOf(END_HL_TOKEN, start_idx);
stringTokenized.Add(clean_temp.Substring(start_idx + 4, end_idx - start_idx));
// Move pointer to start of next section
start_idx = end_idx + 4;
}
}
// END OF MY NEW APPROACH
// Token is at the beginning of the snippet
if (hlItem.IndexOf(START_HL_TOKEN) == 0)
{
hlText = clean_temp.Substring(clean_temp.IndexOf(START_HL_TOKEN) + START_HL_TOKEN.Length,
clean_temp.IndexOf(END_HL_TOKEN) - START_HL_TOKEN.Length);
endText = clean_temp.Substring(clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length,
clean_temp.Length - (clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length));
}
// Token is at the end of the snippet
else if (clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length == clean_temp.Length)
{
startText = clean_temp.Substring(0,
clean_temp.Length - clean_temp.IndexOf(START_HL_TOKEN));
hlText = clean_temp.Substring(clean_temp.IndexOf(START_HL_TOKEN),
clean_temp.Length - clean_temp.IndexOf(START_HL_TOKEN));
}
// Token is in the middle of the snippet
else
{
startText = clean_temp.Substring(0,
clean_temp.IndexOf(START_HL_TOKEN));
hlText = clean_temp.Substring(clean_temp.IndexOf(START_HL_TOKEN) + START_HL_TOKEN.Length,
clean_temp.IndexOf(END_HL_TOKEN) - clean_temp.IndexOf(START_HL_TOKEN) - (END_HL_TOKEN.Length - 1));
endText = clean_temp.Substring(clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length,
clean_temp.Length - clean_temp.IndexOf(END_HL_TOKEN) - END_HL_TOKEN.Length);
}
HighlightItem snippet = new HighlightItem(startText, hlText, endText);
hlList.Add(snippet);
}
HighlightList = hlList;
}
}
So in the model above, I have my old approach where I assumed there would only be one tag in the string but when I realised there are more than 1 sometimes, I started a new approach of building a list representation of the string, marking which parts need to printed normally and which need to be printed highlighted.
Also to my naming standards, only started WPF and C# a month or so ago, so not quite privy to all the naming conventions yet, sorry!