Formatting Text in a ListView? - c#

I'm creating a little app that will read, parse, and format the contents of a lua script - specifically, a SavedVariables file from World of Warcraft created by the "Elephant" chat logging add-on. The prototype I have in mind will generate an array of ListViewItem instances, showing a timestamp, player name, what channel the message was posted into, and the message that was posted.
I'd like to have the chat message rendered as it would be in the game: the game colors the names of those "talking" in the chat after their character's class (e.g. a rogue's name is yellow, mages' names are light blue), but when it comes to ListViewItem and ListViewSubItem, coloring text there seems to be an all-or-nothing deal.
Would it be possible to add functionality for the ListView to apply formatting (or just color) to text in a ListViewItem or ListViewSubItem based on markup in the Text property?
EDIT: I'm asking if it's possible to just add text formatting to a ListViewItem through the magic of inheritance/polymorphism in a derived class, and if so, what's the best way to do it (amount of effort, code security, etc)?

Speaking from a Windows Forms usage view point, you can render the items manually. However you should also consider situations such as: how should the text be rendered when the text exceeds the bounds of the Control/column?
This only requires that you inherit from ListView; you can render each item using:
protected override void OnDrawItem(DrawListViewItemEventArgs e)
Of course, OwnerDraw must be set to true. DrawListViewItemEventArgs contains the text that needs to be rendered and the Graphics instance that should be used to render the text. You could then use DrawString(string s, Font font, Brush brush, float x, float y) to render each part of the text as required by your mark-up convention.
If you don't mind the GPL, ObjectListView does offer more formatting options but perhaps it is not as flexible as you require.
Since a RichTextBox does allows flexible text formatting, I wonder if it could somehow be used as a renderer...

im not completely sure this would work and I cant really test it, but it might be worth a try
<ListViewItem>
<ContentPresenter>
<TextBlock>
<Run x:Name="playerName" Foreground="Blue" Text="NAME"/>
<Run x:Name="etc" Foreground="Black" Text="..."/>
</TextBlock>
</ContentPresenter>
</ListViewItem>
The basic idea here is that in the list box item you have a the content presenter that I think holds the textblock. Within this you can set individual Run tags (bits of individual text) and you can format each one differently. you should also be able to set the text programmatically when the run tags are assigned names

Related

Inserting graphics into RichTextBox

I have just started studying at an university and came up with an idea to manage my transcripts. It's basically a text editor with a small versioning system wrapped around it.
To avoid ending up with walls of black and white text I had the idea to add some presets for "graphics" (not sure what is the right word to use here). For example, if my professor writes down some kind of definition like this one:
Integral
Also called Riemann integral. the numerical measure of the area
bounded above by the graph of a given function, below by the x -axis, and on .........
I would like to wrap it into some kind of different background and styling, just like here on StackExchange on the quote above, with the press of a button. Another example is in one of my books:
Is it even possible to include such styling into a RichTextBox or should I look for alternatives / existing text editors?
Yeah, implementation Example is given to this URL Stack Overflow Answer
and some code for knowledge purpose
//Apply Some Font to selection
richTextBox1.SelectionFont = new Font("Arial", 16);
// Apply same color of text
richTextBox1.SelectionColor = Color.Purple;
//backgroud colour of Selection
richTextBox1.SelectionBackColor = Color.Red;
One more thing is to clearify, if you want to make a text editor, you have to given combo box for colour, size etc, and change this on IndexChange Event.

Why do I have have to use UIElement.UpdateLayout?

We have a rather large WPF business application and I am working on a retool of an existing WPF FixedPage/FixedDocument report.
It's a somewhat busy ecosystem. We have a built-in forms generator, with lots of different controls you can put on (think like a mini built-in visual studio). All that works fine. You fill in the form on the screen, and then you can print out (to XPS) the identical copy to standard 8.5x11 paper.
In the code, we break out this report into vertical chunks. Say each chunk would be an inch or two tall on a printed piece of paper. This is how we handle pagination. If the next chunk is too tall for the page, we do a NewPage() and repeat. As I mentioned, this was working fine.
WPF has an enormous learning curve and I've been going back over old code and refactoring things and happily working with DataTemplates, strongly typed ViewModels, and generic ContentControls in order to reduce the size of our code. The on-screen forms generator still works, but the FixedDocument report has gotten weird.
Going back to those vertical slices, we print the user's forms to paper as individual Grid controls. Nothing fancy. Each grid (as I mentioned above) may be an inch or two high, containing any random mixture of checkboxes, radiobuttons, textblocks, and so on.
When the grids contained these stock (standard) MS WPF controls, I could do this all day long:
System.Windows.Controls.Grid g = .....
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
And get back proper sizes, i.e. 100 x 67.
Now, sometimes the grids have just one control - a header if you will (i.e. "This Month's Schedule). The only child control added to that grid is a ContentControl.
The ContentControl is simply bound to a ViewModel:
<ContentControl Content="{Binding}" />
There's then two DataTemplates in the resource dictionary that picks up this binding. Here, I'll show that:
<UserControl.Resources>
<w:MarginConverter x:Key="boilerMargin" />
<DataTemplate DataType="{x:Type render:BoilerViewModel}">
<render:RtfViewer
Width="{Binding Path=Width}"
TextRTF="{Binding Path=Rtf}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type render:Qst2NodeViewModel}">
<ContentControl Content="{Binding Path=BoilerVm}">
<ContentControl.Margin>
<MultiBinding Converter="{StaticResource boilerMargin}">
<Binding Path="NodeCaptionVm.Height" />
<Binding Path="NodeLeft" />
</MultiBinding>
</ContentControl.Margin>
</ContentControl>
</DataTemplate>
</UserControl.Resources>
The ContentControl will pick up that bottom-most datatemplate. That template will then in turn use the smaller one above.
The fancy converter just sets a margin. It may be fugly to read, but this all displays correctly on the screen within the parent usercontrol. It's all the right size and justification and all that.
On the printed report side (XPS), I have to create these controls in code and measure them to see if they'll fit on the current FixedPage. When I go to do this step: (on the grid containing this ContentControl)
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
I get back 0,0 size. Even though it should be like 730x27 for instance. Again, on the screen, hosted in a UserControl, this all works fine. Just trying to instantiate it and measure it purely in code fails. I've confirmed that the control is added to the grid, has its row and col set, has been added to the Children collection, etc...
If I prepend those two statements with an UpdateLayout call, like this, then it works:
g.UpdateLayout(); //this fixes it
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
I've been reading that UpdateLayout is expensive and to be avoided, and I'd rather not be calling this on each grid section before I add it to my FixedPage of the FixedDocument report. There could be dozens or even hundreds of iterations. And, again, if the Grid has regular WPF controls in it, without any ContentControls and fancy finding and looking up datatemplates, the measuring works fine without the UpdateLayout call.
Any advice? Thank you!
I just don't understand why it became necessary to start calling it once I started utilizing the Xaml engine. It almost feels like I'm being punished for using the advanced features.
Its complicated to explain that but let me try using plain words... In wpf everything works with dispatcher. Futhermore like you may already know dispatcher deals with tasks ordered by priority.
For example first a control is being initalized, then binding is being triggered, then values are updated, in the end all that is being measured.. etc etc
What you managed somehow is by setting all those contentcontrol inside contentcontrol stuff, you screwed up that order
Calling UpdateLayout basically forces dispatcher to finish its pending work in layout so you can work with clean layout afterwards
Screwing with dispatcher is quite common in wpf since some controls or values may be added later which ends in remeasuring things.
In your case you seem to be creating all at once in one method call without letting dispatcher take a breath. Therefore you need UpdateLayout method to normalize dispatchers queue.
I hope this helps you. You can also solve your issue by using Dispatcher.BeginInvoke.
UpdateLayout does not work in my case. I had to wait until dispatcher finishes processing of the layout tasks.
toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);
toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize));
I found another article about this approach.

Pictures that behave as symbols in textbox (or something like textbox)

I need to create a control, that behaves like a textbox, but allows you to replace some (or all) of the characters with pictures that behave (select and remove with backspace/delete) as a normal characters.
I tried to create a RichTextBox inherited control, with "CanPaste - Paste" construction, but the images added this way didn't act like the characters, but as the images which can be resized. It's not a correct solution for me.
So, the question is: How can I override "symbol drawing" method? I mean, get actual (x,y) coordinates of drawing character, and draw picture instead of it (or in front of it). Is that possible?
Control should look similar to this picture. (lockers on picture are images, acting like symbols.)
UPD: Control must be working on systems from XP to 8, so using UTF-8 lock-style symbol won't be a solution for me. Control shown on the screenshot above works in an application that is running on a Windows XP — though I have no idea which way it was implemented.
What I would is use a PasswordBox with a FontFamily="Segoe UI Symbol" and the PasswordChar="& # xE14D;" (remove the spaces). This will render this:
The complete code: <PasswordBox Password="Example" Width="100" FontFamily="Segoe UI Symbol" PasswordChar="" />

How to display large amount of text for ereader application

I need to create a windows store application with e reader functionality. I have to provide a fluid reading experience. Currently, my knowledge of displaying text consists of dropping textblock or textbox on the UI. I do not know how to display large amount of text to create the E Reader experience i am looking for. Which control or combination of controls should i use?
Your text rendering options are
XAML controls
TextBlock
RichTextBlock
WebView + WebViewBrush
DirectWrite - what all the above ultimately use. You can use it with C# through SharpDX.
The controls might be a bit cumbersome to use at times if you need to do measurements etc. and might not give you as much power or performance as DirectWrite does, but will give you support for text selection, copying to clipboard etc. (make sure IsTextSelectionEnabled is set to true).
For measuring text dimensions for paged display in a TextBlock - create a TextBlock in code behind and call Measure() and Arrange(), then get ActualWidth/ActualHeight to get the measurement.
Read Charles Petzold's Principles of Pagination article.
Consider Rapid Serial Visual Presentation (RSVP) speed-reading method used in the ReadQuick app.

Text update slowing down app

I have a Hebrew calendar app where each day is a UserControl. I have 6 labels in that control for the English date, the Hebrew date, Jewish holidays and some other user-defined data. When scrolling, the labels' content changes as the date value for the UserControl goes up or down a week. The scrolling is noticeably slower than Microsoft Outlook Calendar, and profiling reveals that the part taking the longest is updating the label contents, which is not handled by my code.
Is there some way I can make this go faster? MS Outlook seems to have a comparable number of text fields, and the scrolling is smooth.
TextBlocks were not noticeably faster than Labels, but Glyphs gave my calendar whiplash.
Replacing this
<TextBlock Padding="5"
FontFamily="Narkisim"
FontWeight="Bold"
FontSize="20"
Text="{Binding HebrewDate}"/>
with this
<Glyphs Name="HebrewDate"
Margin="5"
StyleSimulations="BoldSimulation"
FontUri = "/Fonts/nrkis.ttf"
FontRenderingEmSize = "20"
UnicodeString = "5771 ןושח ה"
Fill = "Black"/>
made scrolling super fast.
Some notes:
Glyphs do not support binding, so I had to give each one a name and update them in the code behind, like so:
HebrewDate.UnicodeString = zman.HebrewDate;
Glyphs don't have Layout functionality so Hebrew text was coming out backwards. I had to preprocess the Hebrew strings with a reversing function. Even after reversing, the Hebrew vowel points came out misaligned, so I retained Labels for those strings which use vowels.
I can't be sure but it is possible that MS Outlook was coded in something faster than WPF, perhaps using DirectX to show the graphics rapidly.
Otherwise I might suggest toning down on the number of bindings updating at once, I would suggest using an additional thread to gradually update the labels as and when there are spare cycles instead of all at once, which might be causing your stuttering.
To go along with the previous answer, I recommend the background worker. Utilize the background worker for your most time consuming operation that gets executed during the scroll.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Categories