Render numbers for tick on a WPF Slider using TextBox - c#

There have been several earlier questions related to adding number values to the ticks on a WPF Slider (e.g. here and here). All proposed solutions I have found so far are to do with inheriting from the TickBar class and then using DrawText(FormattedText text, Point point) to draw the value. Something like:
protected override void OnRender(DrawingContext dc)
{
foreach(double tick in Ticks)
{
formattedText = new FormattedText(Convert.ToString(tick),
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"), // I don't know why all examples use the Verdana font :P
10, Brushes.Black);
dc.DrawText(formattedText, ComputeTheRightPosition(tick));
}
}
While this is a valid solution, I am finding that it is not generic enough for me, due to the FormattedText. In my application, the Style can change at runtime, so I would prefer a way of putting all the numbers in a TextBlock or something, which can dynamically update its style and font and all.
Is it possible to add text boxes in this way in anSlider or TickBar subclass?

Out of the box solution -
Put a canvas above the slider. When slider value changes, get a ratio of value / (max-min)
Use the same ratio to place the textblock in the canvas using SetLeft or Render Transform.

Related

Get number of rows of a text

I have a string that can be anything and I have a text object in my scene which has a set width and a changeable height.
Is there a built-in function that counts how many rows my string would have in that text object so that I can adjust the height of it? I want to do this because I need a background only at the text and not anywhere else.
I want to do this because I need a background only at the text and not anywhere else.
It appears to me that this should be able to solve your problem:
In order to make a Rect Transform with a Text component on it fit the text content, add a Content Size Fitter component to the same Game Object which has the Text component. Then set both the Horizontal Fit and Vertical Fit dropdowns to the Preferred setting.
In your case you want to control the Horizontal but not the vertical, so try set the Vertical setting to "Preferred".
If this does not work directly on your text component you may want to make the text component a child of the grey panel box and then add the contentfitter to it as well.
Source: https://docs.unity3d.com/Manual/HOWTO-UIFitContentSize.html
Disclaimer: I didn't test this Component based attempt, but I believe it may be the solution or lead you closer to one.
While Doh09's answer is certainly accurrate, you can also query the UI.Text.preferredHeight property, asking the Text object how tall the text is and using that value to change the size of your background object yourself.
Of course, both answers assume you are using the New UI text and not TextMesh or OnGUI. If you are not using the New UI, then I suggest changing to using the New UI.
You can see an example usage of this in my own project here where I compute the text's desired width and height and modify the RectTransform until the object's preferred size is within a layout-preferred ratio. Here's one of the final sections (with some alterations to make it understandable):
Text t = <some Text object>
float height = t.preferredHeight;
float width = t.preferredWidth;
((RectTransform)tooltipGO.transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, (width / 4) + 8);
((RectTransform)tooltipGO.transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, (height / 4) + 7.5f);
The divide-by-four and offsets to account for relative scaling between the text and the background and some edge padding.

Setting Width of Textbox according to maxlenth

I am using winforms application and i want to set that width of textbox which will show characters till max length,in short something like width = maxlength.Any predefined property is there? or we have to calculate it manually?
//I am looking for this type of logic
private void Form1_Load(object sender, EventArgs e)
{
//sample project
textBox2.Width = textBox2.MaxLength;
textBox3.Width = textBox3.MaxLength;
textBox4.Width = textBox4.MaxLength;
}
You have a Unit Mismatch: Width is in Pixels, MaxLength in characters.
So you need to measure the Font using e.g. Graphics.MeasureString.. Works best for fixed Fonts like Consolas.
You can measure the font e.g. like this, using 'x' as a medium width letter:
using (Graphics G = textBox2.CreateGraphics())
textBox2.Width = (int) (textBox2.MaxLength *
G.MeasureString("x", textBox2.Font).Width);
There are other Font measurement methods like TextRenderer.MeasureText you could use; also both methods have options to fine tune the measurement. The default above will include some leeway.
If you use a fixed Font the width will be OK, if you don't you'll need to decide whether you'd rather be on the safe side (use "W" or "M" to measure) or not. "X" is a likely compromise. Or you could adapt dynamically in the e.g. the TextChanged event..
Use the Anchor property to define how a control is automatically resized as its parent control is resized
Anchoring a control to its parent control ensures that the anchored edges remain in the same position relative to the edges of the parent control when the parent control is resized.
Try this:
textbox1.MaxLength = 0//The default value is 0, which indicates no limit;
Refer this msdn link for more info:
msdn link for textbox maxlength

How to override the StrokeThickness property of a Line in WPF

Here is the problem that has been with me for the past several days. I have 10000+ Line objects on a Canvas and a Slider that I use to scale the canvas to create a zoom effect.
Everything is OK and the performance is great.
The only thing that bothers me is that the StrokeThickness of the Line gets scaled too. I tried to Bind the StrokeThickness to the inverse of the slider's value so that I get a uniform thickness whenever I move the slider. This worked but has decreased the performance substantially.
Is there any other way that would be suitable to this situation. I want to have a zero-width line thickness no matter how far I scale the canvas (like in CAD programs).
For the effect you want to achieve, overriding the StrokeThickness doesn't really mean anything as the it's value actually remains the same even if the ScaleTransform is changed.
The approach that you tried - Bind the StrokeThickness to the inverse of the slider's value - seems to be the most plausible one. To improve performance, instead of setting the StrokeThickness directly to inverse of Slider's value, set it to another property on your view model.
Then, in the event where sliding is completed, set the value of that property to the inverse of StrokeThickness.
Example -
private void OnSlidingComplete(object sender, EventArgs e)
{
LineStrokeThickness = GetInverseOfZoomValue();
}
I know that this is not exactly a solution, rather a workaround.

Dynamic Data Display - WPF - Need to add text to canvas - C#

I am using the dynamic data display WPF chart. I have a requirement to display a label next to every point on the curves plotted on the chart.
The exact functionality is as follows:
Every curve has a an object that holds its data and a description that inculdes color, marker shape etc. It also tell me whether the labels must be visible for that particular curve.
There is also an option using a checkbox to hide/show the labels for all points on all the curves on the plot.
There is a third option where a user can left click on the marker and see a label next to it.
Now, I previously implemented it by adding labels along with the ElementMarkerPointGraph for each point and setting the visibility of the labels. I know there is a massive performance hit with this approach.
I am now looking to create a solution where I can render text directly to the canvas at a location that I provide. I also need help with the removing the text from the canvas.
Is there a way of adding text natively to the canvas? What is the most efficient way to do so?
EDIT: I need to move the text around as the plotter zooms. I already know when the plotter zooms, I need to be able to move the text to the appropriate location.
I'm not sure whether this will give you the zooming purpose but the code below can be used to add text inside a canvas..I got it from a site while googling.
private void Text(double x, double y, string text, Color color)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = text;
textBlock.Foreground = new SolidColorBrush(color);
Canvas.SetLeft(textBlock, x);
Canvas.SetTop(textBlock, y);
canvasObj.Children.Add(textBlock);
}
OK. My exact implementation can't be put up here. But I can provide some idea of how to do it.
So create a simple user control that derives from Canvas.
class CustomCanvas : Canvas
{
protected override void OnRender(DrawingContext dc)
{
FormattedText someFormattedText = new FormattedText(someText, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
someTypeFace, someFontSize, someColor);
dc.DrawText(someFormattedText, new Point(15, 15));
}
}
You can seal the class, if you do not want it subclassed/overriden further.
That's about it. You can check out the other methods available with the drawing context to do some other stuff. :)
I figured it out myself. I'll be overriding the OnRender method to handle this. I can draw text using the drawing context.

How to make OnRender() draw above the control, not below?

I want to draw underlines in textboxes with the OnRender method but the line is drawn behind the textbox. The textbox is opaque so the underline won't be visible. How can I draw something above the textbox?
protected override void OnRender(DrawingContext dc){
dc.DrawLine(new Pen(new LinearGradientBrush(Colors.Green, Colors.Blue, 0.0d), 2), new Point(0, Height - 4), new Point(Width, Height - 4));
}
By the way, why does everyone use "base.OnRender(drawingContext);" in their OnRender() Methods? It does not change anything for me.
I can't use TextDecoration because the underline must be drawn even if there is no text.
Edit:
Might not be a beautiful solution but it seems like there is no better way:
The OnRender() Method draws the background and after that, the line. The TextBox Background property is set to null so the background won't be drawn again.
Just a gess: Do you tryied to call base.OnRender() before drawing your line ?
in an override like that you'd better always leave the base method call, like in your case
base.OnRender(dc);
if you remove it your override has to draw/render everything and the base class won't render anything. In general depends on usage patterns and scenarios of course but generally removing it is dangerous.
Edit: as for your question, it seems not easy to override/customize the rendering behaviour of WPF TextBox, I found this one:
Customizing WPF TextBox Not Easy, But Possible

Categories