How do I set a ScrollBar's value when it grows dynamically? - c#

I'll start by what I'm trying to have happen:
I have data loaded in a range, where, say, scrolling all the way to the left puts me on April 1, and scrolling all the way to the right puts me on June 1.
The user positions the scrollbar on April 1st, and clicks the left arrow on the scrollbar. Now the scrollbar is positioned at March 31, and the range of data now spans from March 1-June 1.
Here's my problem:
I have been handling the left-arrow-click in the Scroll event handler (roughly as follows):
private void horizontalScroll_Scroll(object sender, ScrollEventArgs e)
{
if (LeftArrowClicked())
{
horizontalScroll.Maximum = calculateNewMaximum(earliestDate, latestDate);
horizontalScroll.Value = calculateNewPosition(currentDate.AddDays(-1), earliestDate);
}
}
Stepping through with the debugger, the moment it leaves this event handler, horizontalScroll.Value drops to 0, while horizontalScroll.Maximum stays at the correct value.
I'll post back later with any clarifications, and answers to questions.

Try setting e.NewValue instead of horizontalScroll.Value. The control will then respect this value when executing its own logic.

It's clearly being caused by the ScrollableControl setting the value after the Scroll event is fired. You could try extending the control you are using and overriding the OnScroll virtual method.
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
// Do stuff now
}
Edit
You should probably be aware that clicking a scroll bar's buttons does not raise the Scroll event, it only raises the ValueChanged event. (Using the mouse generates both though.)
Edit Again
Ah ha! I knew there was a way to do it. What you want to do instead of changing horizontalScroll.Value, you want to set the NewValue on the ScrollEventArgs parameter. This should work:
private void horizontalScroll_Scroll(object sender, ScrollEventArgs e)
{
if (LeftArrowClicked())
{
horizontalScroll.Maximum = calculateNewMaximum(earliestDate, latestDate);
e.NewValue = calculateNewPosition(currentDate.AddDays(-1), earliestDate);
}
}

Related

C# Checkbox not gaining focus on Tabstop

I am making a config editor form and have hit a bit of an issue, I put a lot of time into userfriendly and efficient design and therefor want the TabIndex to work perfectly to minimize use of mouse.
My problem is now when I try to tab through the controls I noticed the CheckBox was not gaining focus like if you press it with the mouse, this means I couldn't tab through and change their state directly from keyboard.
How do I make the CheckBox gain focus via TabIndex and TabStop so that I can just press Enter to change its state via the KeyUp event.
Below is a picture of my form, and next to it a picture of the TabIndex as well as a the code taken directly from the Form.Designer.cs class.
//
// cbxDefaultPublic
//
this.cbxDefaultPublic.AutoSize = true;
this.cbxDefaultPublic.Location = new System.Drawing.Point(247, 12);
this.cbxDefaultPublic.Name = "cbxDefaultPublic";
this.cbxDefaultPublic.Size = new System.Drawing.Size(15, 14);
this.cbxDefaultPublic.TabIndex = 1;
this.cbxDefaultPublic.TabStop = true;
this.cbxDefaultPublic.UseVisualStyleBackColor = true;
Please note that I had a hard time explaining this cause its a bit complicated and didn't know how to explain it so bare over with me if I got a few things wrong.
With the help of the people commenting on my question I was able to get on the right track of what to do and what to search for.
Thanks to Grant Winney, LarsTech and JohnnyBoy for explaining to me how the CheckBox worked and what I needed to look at.
I found out that the CheckBox does not have a public highlight feature so I had to get creative.
What I did was I created a custom CheckBox and well.. might just show you the code :P
public class MyCbx : CheckBox {
protected override void OnGotFocus(EventArgs e) {
base.OnGotFocus(e);
base.OnEnter(e);
base.OnMouseEnter(e);
}
protected override void OnLostFocus(EventArgs e) {
base.OnLostFocus(e);
base.OnLeave(e);
base.OnMouseLeave(e);
}
protected override void OnMouseLeave(EventArgs e) {
if(!this.Focused) {//prevent it from losing highligh if control is in focus
base.OnMouseLeave(e);
}
}
}
So I call the MouseEnter and Leave events when It gain or lose focus, this will make it change to a highlighted state.

C# set text box cursor position works if a breakpoint is hit, not otherwise

Environment: VS 2012 on Win7 Pro box.
I have a control I derived from TextBox. The control's text is initialized to "00". I want to make sure that the cursor is positioned at the end of the text string, if it exists, whenever the control becomes active.
I have three of these controls contained in a user control. I can only get the cursor positioning to work the way I want it if all of the following are true:
I have overridden OnEnter() in my textbox-derived control.
I have overridden OnGotFocus() in my textbox-derived control.
I am running my test form in the debugger.
I have a breakpoint set at the start of OnEnter().
Here are my overrides:
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
if (Text.Length > 0)
{
SelectionStart = Text.Length;
}
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
if (Text.Length > 0)
{
SelectionStart = Text.Length;
}
}
Thank you very much.
The code you wrote does work when you switch to the textbox using the tab key (I just tested it to confirm).
It doesn't work when you click the textbox with the mouse. The reason for that is probably due to the fact that dot net sets the caret to the mouse cursor location, and it does that after the GotFocus event gets fired (and the GotFocus event is fired after the Enter event is fired, according to this link: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.gotfocus(v=vs.110).aspx).
I don't have an elegant solution to this, but until somebody comes up with something better, you can add a small delay (which is what happens when you break with the debugger) which seems to work fine for me:
protected override async void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
await Task.Delay(10);
if (Text.Length > 0)
{
SelectionStart = Text.Length;
}
}

Check time after a mousebuttondown before the mousebuttonup

I think that must be only a little problem, but I can't get a clear thought on that. Someone an idea?
I have some borders on a canvas (filled with images) and i want to click the border (i do this with the OnMouseLeftButtonDown) where the border gets red (so the user knows for sure which object he had clicked) and then, after 1 or 2 seconds, when the mousebutton is still pushed down, a drag'n'drop should start.
At first I had the borders inside buttons, but the clickevent seems to conflict with the dragevent. So I got rid of the buttons and did everything inside the borders directly, which works well also. But how can I start the drag after the mousebuttondown and stop it when the mousebuttonup happens before the time runs out.
Someone an idea for a clean solution?
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_source = sender as Border;
Mouse.Capture(_source);
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_source = null;
Mouse.Capture(null);
}
and in event OnMouseMove you can modify border margins depends on mouse position but after checking if _source is type of Border.
var position = e.GetPosition(Canvas);
EDIT:
For that time you can add property Stopwatch _watch, and inside OnMouseLeftButtonDown event handler you can do it:
_watch = Stopwatch.StartNew();
in OnMouseLeftButtonUp:
_watch.Stop();
and in OnMouseMove before your code:
while (_watch.ElapsedMilliseconds < 2000 && _watch.IsRunning)
{
Thread.Sleep(100);
}

Update mediaElement based on slider value

I have a mediaElement and a slider.
The slider's maximum value is video's duration in seconds (for example if the video is 2 minutes, the slider's value is 120).
I want to update the mediaElement.Position based on the slider's value but the problems is that I dont want to update the position until the user FINISHED manipulating the value.
so what I did is 2 functions:
private void DurationSlider_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
SeekToMediaPosition();
}
this function applys if the user stopped manipulating the slider.
private void DurationSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
SeekToMediaPosition();
}
this function applys if the user clicked on different value in the slider.
The problem is that they clash.
Manipulating the slider cause the value to be changed...
so What I did is added this function:
bool manipulating = false;
private void DurationSlider_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
manipulating = true;
}
and in the ValueChanged function I checked whether manipulating = true or not
It solved half of the problem - it does not change the video position while manipulating (until I finish) but if I click on different position on the slider (without releasing the mouse) and continue manipulating the slider's value - it changes the video position to where I clicked on the slider and then changes again to where I ended the manipulation.
So whats wrong?
I want to change the video position ONLY when the user released the mouse.
I cant find event that fires what I want...
You could use PointerCaptureLost Event to determine the position after the user finished dragging the control.
<Slider PointerCaptureLost=="Slider_PointerCaptureLost"
Height="27" Margin="132,162,0,0" VerticalAlignment="Top" Width="303"/>
Then in code behind.
private void Slider_PointerCaptureLost(object sender, DragCompletedEventArgs e)
{
Slider s = sender as Slider;
// Your code
MessageBox.Show(s.Value.ToString());
}

Drawing in C# winform is fairly slow

I'm creating a custom DataGridView, in which the CheckBox Shows a border when MouseHover is raised.
Here is what I've done so far.
void checkBox_MouseLeave(object sender, EventArgs e)
{
//showBorder defines whether the border is drawn.
this.showBorder = false;
this.DataGridView.InvalidateCell(this);
}
void CheckBoxMouseHover(object sender, EventArgs e)
{
this.showBorder = true;
this.CheckBox.BringToFront();
this.DataGridView.InvalidateCell(this);
}
protected override void Paint(...........)
{
..........
if (showBorder)
{
GraphicsPath border=new GraphicsPath();
border.AddRectangle(new Rectangle(checkBoxPosition.X-1,checkBoxPosition.Y-1,checkBoxSize.Width+1,checkBoxSize.Height+1));
graphics.DrawPath(new Pen(borderColor,1),border);
}
}
But is comes so slow that I have to wait for about half a second to see do border show.
Anyway, MouseLeave works fine.
So how can I improve the performance here?
In addition, how can I customize the checkbox? for example, the background color, etc.
You're using MouseHover event for the Mouse going over the control. Try MouseEnter instead. MouseHover is triggered after the mouse stays over the control for a little bit of time. MouseEnter is instant

Categories