I can't change brush size in SurfaceInkCanvas - c#

I am having difficulties to understand why I can change the brush color but can't change the brush radius in a SurfaceInkCanvas.
Here is what I do:
Double newSize = Math.Round(BrushRadiusSlider.Value,0);
drawingAttributes = new System.Windows.Ink.DrawingAttributes();
// Works :
drawingAttributes.Color = Colors.Yellow;
// Does not work :
drawingAttributes.Width = newSize;
drawingAttributes.Height = newSize;
canvas.DefaultDrawingAttributes = drawingAttributes;
For information, BrushRadiusSlider is a slider in the XAML and gives values between 1 and 100.

See here:
SurfaceInkCanvas.DefaultDrawingAttributes Property
You probably forgot to set the UsesTouchShape to false

The issue is I think that the brush is not updating when the slider's value is changed. Your code above takes the value of the slider at one moment in time, and sets the width and height to that, but it is not linked to the slider.
To get it to update when the slider changes you would need to handle the SliderValueChanged event and reset the drawingAttributes then.
XAML:
<Slider x:Name="BrushRadiusSlider" Minimum="1" Maximum="100" Value="1" ValueChanged="SliderValueChanged"/>
Code:
private void SliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (canvas != null)
{
var drawingAttributes = canvas.DefaultDrawingAttributes;
Double newSize = Math.Round(BrushRadiusSlider.Value, 0);
drawingAttributes.Width = newSize;
drawingAttributes.Height = newSize;
}
}

Related

AutoSize text in a fixed-sized label to avoid text jumping to second line

I have a label with a fixed size, approximately 100 pixel width and 20 pixel height.
When I place a long string into the label, the text wraps to the second line but I cannot see the second line because the size of the label is fixed.
Instead of wrapping to the second line, I want the fontsize to shrink so that the string is displayed on a single line in the label. Does anyone know of a simple way to do this?
EDIT:
The below code is working for me (most of the time). I didn't want to do anything recursive. There are times when the text still spills over to another line. I assume because I can't truly use the entire width of the label. How do I compensate for that?
private void Label_TextChanged(object sender, EventArgs e)
{
Label label = sender as Label;
if (label != null && label.Text.Length != 0)
{
SizeF size = new SizeF();
using (Graphics g = label.CreateGraphics())
{
size = g.MeasureString(label.Text, label.Font);
}
Single x = (label.Width) / size.Width;
Single y = (label.Height) / size.Height;
Single scaler = x > y ? y : x;
using (Font font = label.Font)
{
label.Font = new Font(font.Name, font.SizeInPoints * scaler);
}
}
}
This is easy to do. Use Graphics.MeasureString(...) to determine the width required for your string, then progressively make the font smaller and smaller until the width required for the string is equal to or less than the width of your label.
You can use the System.Windows.Forms.Label.TextChanged-event and check the length of the string.
private void Label_TextChanged(object sender, EventArgs e){
System.Windows.Forms.Label label = sender as label;
if(label != null){
//check text-length and if necessary resize it
}
}
See here for TextChanged-event.
There is the FontHeight-property, which might do your trick. See here for a reference.
And if everything fails, derive from System.Windows.Forms.Label and create your own custom label.

How to make WPF Slider Thumb follow cursor from any point

I have such slider:
<Slider Minimum="0" Maximum="100"
TickFrequency="1"
IsMoveToPointEnabled="True"
IsSnapToTickEnabled="False"/>
I want to make next behavior:
when MouseDown occured at any point of slider, Thumb not only moves once to that point, but also following cursor until MouseUp occurs.
Sorry if it was asked already, i couldn't find that question.
This behavior will happen only when you drag the slider thumb itself, it is by design.
However, here's some code that will do it ;-)
Hook to the MouseMove event in XAML:
<Slider MouseMove="Slider_OnMouseMove" IsMoveToPointEnabled="True"/>
Then insert this code:
private void Slider_OnMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
var slider = (Slider)sender;
Point position = e.GetPosition(slider);
double d = 1.0d / slider.ActualWidth * position.X;
var p = slider.Maximum * d;
slider.Value = p;
}
}
Note :
You might have to take margins and padding of your slider into account should they differ, I haven't.
This was done on an horizontal slider.
Minimum value of my slider was 0, make sure to adjust the calculation should your minimum be negative.
Finally, it does seem to work only when IsMoveToPointEnabled is set.
Aybe's solution works better in the thumb_MouseMove event.
void timelineThumb_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
var thumb = sender as Thumb;
Point pos = e.GetPosition(uiVideoPlayerTimelineSlider);
double d = 1.0d / uiVideoPlayerTimelineSlider.ActualWidth * pos.X;
uiVideoPlayerTimelineSlider.Value = uiVideoPlayerTimelineSlider.Maximum * d;
}
}

Dynamic Fontsize for TextBlock with wrapping

I have a TextBlock with a fixed size thats wrapping text. sometimes short sometimes long.
If the text is getting to long it isnt displayed entirely like this
How can i make the Fontsize flexible to make the text fit the TextBox with static size?
My solution is the following:
Set the fontsize to a value, than which you don't want any bigger.
The ActualHeight of the TextBlock changes, when you change the font size or when the content is changed. I built the solution based upon this.
You should create an event handler for the SizeChanged event and write the following code to it.
private void MyTextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
double desiredHeight = 80; // Here you'll write the height you want the text to use
if (this.MyTextBlock.ActualHeight > desiredHeight)
{
// You want to know, how many times bigger the actual height is, than what you want to have.
// The reason for Math.Sqrt() is explained below in the text.
double fontsizeMultiplier = Math.Sqrt(desiredHeight / this.MyTextBlock.ActualHeight);
// Math.Floor() can be omitted in the next line if you don't want a very tall and narrow TextBox.
this.MyTextBlock.FontSize = Math.Floor(this.MyTextBlock.FontSize * fontsizeMultiplier);
}
this.MyTextBlock.Height = desiredHeight; // ActualHeight will be changed if the text is too big, after the text was resized, but in the end you want the box to be as big as the desiredHeight.
}
The reason why I used the Math.Sqrt() is that if you set the font size to half as big as before, then the area that the font will use, will be one quarter the size, then before (because it became half as wide and half as tall as before). And you obviously want to keep the width of the TextBox and only change the height of it.
If you were lucky, the font size will be appropriate after this method gets executed once. However, depending on the text that gets re-wrapped after the font size change, you might be so "unlucky", that the text will be one line longer than you would want it to be.
Luckily the event handler will be called again (because you changed the font size) and the resizing will be done again if it is still too big.
I tried it, it was fast and the results looked good.
However, I can imagine, that in a really unlucky choice of text and height, the correct font size would be reached after several iterations. This is why I used Math.Floor(). All in all, it doesn't matter much if the font size is in the end 12.34 or 12 and this way I wouldn't be concerned about an "unlucky" text, which will take too long to render.
But I think Math.Floor() can be omitted if you don't want to have a really tall text box (like 2000 pixels) with a lot of text.
Here's a full solution including an option to set maxheight / maxwidth and and it is calculated straight on render:
public class TextBlockAutoShrink : TextBlock
{
private double _defaultMargin = 6;
private Typeface _typeface;
static TextBlockAutoShrink()
{
TextBlock.TextProperty.OverrideMetadata(typeof(TextBlockAutoShrink), new FrameworkPropertyMetadata(new PropertyChangedCallback(TextPropertyChanged)));
}
public TextBlockAutoShrink() : base()
{
_typeface = new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, this.FontStretch, this.FontFamily);
base.DataContextChanged += new DependencyPropertyChangedEventHandler(TextBlockAutoShrink_DataContextChanged);
}
private static void TextPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var t = sender as TextBlockAutoShrink;
if (t != null)
{
t.FitSize();
}
}
void TextBlockAutoShrink_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
FitSize();
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
FitSize();
base.OnRenderSizeChanged(sizeInfo);
}
private void FitSize()
{
FrameworkElement parent = this.Parent as FrameworkElement;
if (parent != null)
{
var targetWidthSize = this.FontSize;
var targetHeightSize = this.FontSize;
var maxWidth = double.IsInfinity(this.MaxWidth) ? parent.ActualWidth : this.MaxWidth;
var maxHeight = double.IsInfinity(this.MaxHeight) ? parent.ActualHeight : this.MaxHeight;
if (this.ActualWidth > maxWidth)
{
targetWidthSize = (double)(this.FontSize * (maxWidth / (this.ActualWidth + _defaultMargin)));
}
if (this.ActualHeight > maxHeight)
{
var ratio = maxHeight / (this.ActualHeight);
// Normalize due to Height miscalculation. We do it step by step repeatedly until the requested height is reached. Once the fontsize is changed, this event is re-raised
// And the ActualHeight is lowered a bit more until it doesnt enter the enclosing If block.
ratio = (1 - ratio > 0.04) ? Math.Sqrt(ratio) : ratio;
targetHeightSize = (double)(this.FontSize * ratio);
}
this.FontSize = Math.Min(targetWidthSize, targetHeightSize);
}
}
}

Why is my RenderTransform only occuring once?

I have a rectangle and on my MouseMove event I want to transform the rectangle whenever the rectangle's width has changed.
I have code sorta like this:
private Rectangle _rectangle;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_rectangle = GetTemplatedChild("PART_RangeRectangle") as Rectangle;
if(_rectangle != null)
{
_rectangle.MouseMove += new MouseEventHandler(_rectangle_MouseMove);
}
}
private void _rectangle_MouseMove(object sender, MouseEventArgs e)
{
if(e.LeftButton == MouseButtonState.Pressed && _rectangle != null)
{
_rectangle.Width += 50;
_rectangle.RenderTransform = new TranslateTransform(-10, 0);
}
}
My Xaml looks sorta like this:
<Grid>
<Canvas>
<Rectangle Name="PART_RangeRectangle" StrokeThickness="5"
RenderTransformOrigin="0.5, 0.5" />
<Canvas>
</Grid>
When I first trigger the MouseMove event the translation occurs as expected. But this only occurs once. I am getting into that block of code and the width of the rectangle is updating fine, but I've yet to figure out why the transform is not updating.
You're replacing the old transform with an identical transform. You need to modify the existing transform and use += like you do with Width.
Example:
if (_rectangle.RenderTransform is TranslateTransform)
{
(_rectangle.RenderTransform as TranslateTransform).X -= 10;
}
else _rectangle.RenderTransform = new TranslateTransform(-10, 0);
You're not changing your transform. Assigning a RenderTransform does not move the rectangle, it sets an offset. You're not changing that offset after your first assignment.

How to set threshold in windows progressbar control?

I am using windows progressbar in winform. It's minimum value is 20 and maximumm value is 120. I have to set threshold in the progressbar for value=60 such that if value remains below 60 then progressbar colour will be red else if value is more than 60 then progress bar colour should be green.
And the most important thing is that I want to show this threshold value as a line in progessbar that should be visible whatever may be the colour of progressbar green or red.
Does anybody have idea?? Your help will be appreciated.
You can try this (However you won't get animation).
It a modified version of this answer with Threshold features added.
public class NewProgressBar : ProgressBar
{
//This property takes the Threshold.
public int Threshold{ get; set; }
public NewProgressBar()
{
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rec = e.ClipRectangle;
rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4;
if(ProgressBarRenderer.IsSupported)
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
rec.Height = rec.Height - 4;
//Check value is greater that Threshold
if(this.Value > Threshold)
{
e.Graphics.FillRectangle(Brushes.Green, 2, 2, rec.Width, rec.Height);
}
else
{
e.Graphics.FillRectangle(Brushes.Red, 2, 2, rec.Width, rec.Height);
}
//This line should do that
e.Graphics.DrawLine(Pens.Black,Threshold-1,2,Threshold-1,rec.Height);
}
}
Now you can use it like this:
NewProgressBar p = new NewProgressBar();
//Set properties
//Set threshold
p.Threshold = 60;
With the default ProgressBar implementation, you will not be able to completely achieve what you want.You would need to create a custom control.
If you are interested in changing the color only, you can achieve that by changing the ForeColor property when the percentage value changes.

Categories