How to know when scrollbar position in the end - c#

I have GridControl (DevExpress) of form. I want to call some method when position of vertical scrollbar in the end. Is this possible? Thanks.
EDIT
My solution(not exactly solve the question, but work great for me):
void gvDisplay_TopRowChanged(object sender, EventArgs e)
{
if (gvDisplay.IsRowVisible(gvDisplay.RowCount - 1) == RowVisibleState.Visible)
{
_lastFocusedRowHandle = gvDisplay.RowCount;
LoadNextPortionOfData();
}
}

I haven't used devexpress before but the way in going about handling this should still be the same or similar regardless as you will still need to create your own extended event. The following is what would be done for the default windows forms, if devexpress extends on this then there should be no problem.
Handling this would be done by an event being triggered. The component class you are using should have a Scroll event, this event is called when the position of the scroll bar changes. If you create a new component class and have it inherit from the component class you want you can then add features that you want. In this new component class you need to extend the event Scroll to check the Value property of the scrollbar. When using this new component class it will still have all the functionality that the original had but now with the new features you added.
For more reading:
Scrollbar class
http://msdn.microsoft.com/en-us/library/t2htecew.aspx
Scrollbar Scroll event
http://msdn.microsoft.com/en-us/library/system.windows.forms.scrollbar.scroll.aspx

Related

BeginResize/EndResize Event for Control on WinForms Design Surface

TLDR: I would like to know how I can create a hook into a begin-resize and an end-resize event for a design-time control instance on the designer surface.
Detail: Specifically, I am working with a design surface produced by a BasicLoader in the System.Design and System.Component.Design .NET namespaces. Specifically, I'm working a design-time instance of the TableLayoutPanel. That control exposes a SizeChanged event and a Resize event--alas, both fire during the resize operation--that is, while the control is being resized--as well as when the resize operation is complete. I therefore have no way of know when the resize operation began and when it officially ended.
One way to tackle this would be to detect a mouse-down event along with a resize event--but it's unclear to me how I can detect a mouse-down event on any of the grab handles of a control being resized.
For the records, I revisited the BehaviorService and saw that it exposes BeginDrag, EndDrag, and Synchronize--I see nothing in that service that would help me with BeginResize/EndResize events.
So, ideally, I would like to subscribe to BeginResize/EndResize events for any designer instance of a Winform control, but I would be happy if the provided answer covered only my need to have these events attached to a designer instance of the TableLayoutPanel control...
Any thoughts?
When a resize starts, a designer transaction with a specific description starts and when the design ends, the transaction will be closed.
You can rely on TransactionOpened event of the IDesignerHost and check the TransactionDescription to see if it starts with "Resize", set a flag resizing to true. Then in TransactionClosed you can check if the flag is true, it means it's a resize end has happened.
Example
Here is a PoC to show how it works. Add the following control into a Windows Forms project and after building the project, drop an instance of MyControl on the form. Then if you try to resize the form, you will see the Resize started. and Resize ended. text on title-bar of the form:
Here is the code:
using System;
using System.ComponentModel.Design;
using System.Windows.Forms;
public class MyControl : Control
{
IDesignerHost host;
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if(DesignMode)
{
host = (IDesignerHost)Site.GetService(typeof(IDesignerHost));
host.TransactionOpened += Host_TransactionOpened;
host.TransactionClosed += Host_TransactionClosed;
}
}
bool resizing = false;
private void Host_TransactionOpened(object sender, EventArgs e)
{
if (host?.TransactionDescription?.StartsWith("Resize") == true)
{
resizing = true;
((Control)host.RootComponent).Text = "Resize Started.";
}
}
private void Host_TransactionClosed(object sender,
DesignerTransactionCloseEventArgs e)
{
if (resizing)
{
resizing = false;
((Control)host.RootComponent).Text = "Resize ended.";
}
}
}
If you want to do some R&D before going with this solution, you may want to take a look at the following classes (mostly internal) in System.Design assembly: GrabHandleGlyph, ResizeBehavior.

Winforms Designer: How to disable my usercontrol from being a container?

I have a relatively simple setup. I have a custom usercontrol that has a bunch of components on it, some text boxes, and a listview.
In the designer, I can drag and drop other controls into my usercontrol, and it adds them to the usercontrol instance. I don't want this.
How can I explicitly say "Don't allow additional controls to be added to this usercontrol?"
That's not the way it works. When you drop your user control on a form then adding controls to it isn't supported. That requires a special designer, this answer shows what is required. Maybe it looks like the controls get added but they merely overlap your user control. Their parent is still the form.
If a programmer opens your user control class itself in the designer then, sure, he can add controls as he pleases. The only way to stop that is to not ship the source code and use the sealed keyword to prevent deriving from it.
You could create a boolean property MyContainer.DisableAddControls or something.
If your MyContainer.Controls.Add(..) is overridden, then you can throw some custom exception in that Add() method as follows:
if(DisableAddControls)
{
throw new DisableAddControlsException();
}
If you are inheriting that method straight from ContainerControl, then you can handle the ControlAdded event and throw the exception there.
myContainer.ControlAdded += myContainerControlAdded;
private void Control_Added(object sender, System.Windows.Forms.ControlEventArgs e)
{
if(DisableAddControls)
{
throw new DisableAddControlsException();
}
}
On second thought, this won't throw out your designer at design time... nevermind.

AutoCompleteComboBox Arrow Up/Arrow Down keys to scroll list

I created a simple AutoCompleteBox in my WPF app and it loads great with code intercepting the Populate event, but when the list pops up and I hit the arrow down key and get to the end of the list the vertical scroll bar doesn't scroll.
The values keep changing in the field like it is scrolling through them, but the scroll bar doesn't move.
If I use the mouse it scrolls fine.
I just need the arrow key to scroll it.
Any ideas/suggestions?
I am new to WPF and have searched forever for this fix.
Attach a SelectionChanged event and then, inside the handler:
private void AutoCompleteBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
AutoCompleteBox box = (AutoCompleteBox)sender;
ListBox innerListBox = (ListBox) box.Template.FindName("Selector", box);
innerListBox.ScrollIntoView(innerListBox.SelectedItem);
}
I see the same behavior. I found a post on codeplex talking about a different issue but at the bottom of the post they have a class AutoCompleteBoxEx that supports ScrollIntoView, so you can hook up the SelectionChanged even and this should get you the behavior you want. I have no idea why this is not baked in. I have had a chance to test out the posted code.
Update
Just pasted the code from the post into a class and used it in the XAML by changing AutoCompleteBox to AutoCompleteBoxEx and adding namespace for AutoCompleteBoxEx and it worked fine. You don't have to specify any event in the XAML, nor do you need to add any code to the code behind.

WPF event handling between objects

I'm pretty new to C#/WPF, coming from Obj-c background. I'm not really sure how this works in terms of object oriented design, and how different classes see each other.
So I have a large view (MainView) that has some custom plots and a datagrid on the bottom (Datagrid is in its separate xaml and has .cs file behind it). There is a custom object that gets added to the plots that when you drag it, the datagrid gets updated (by using dataGrid.ScrollIntoView). The code for the ScrollIntoView is in the xaml.cs file of the Datagrid.
To me this makes sense since the MainView has all the components and "sees" all the objects, so when the event handler of the dragWindow gets called, then the MainView asks for the DataGrid, and calls its method to update its column position. (This is the way I understand it, please feel free to correct me if I'm wrong).
Now I want to go the other way as well. So that if I update the scrollbar horizontally, then the dragwindow in the MainView will get updated. This does not make as much sense to me. I can create an event handler in the xaml.cs of the datagrid. But it does not see the dragWindow in the MainView right? So I'm not quite sure how to start implementing this functionality. Any help is always appreciated. Thanks!
Your grid control should expose an event to notify any consumers (MainView in this case) that scrolling has taken place.
public class YourGridControl
{
public event EventHandler GridScrolled;
}
MainView can then attach a handler to this event in the designer or in the code:
gridCtrl.GridScrolled += OnGridScrolled;
private void OnGridScrolled(object sender, EventArgs e)
{
// Logic here
}

How to inherit base Textbox to provide colored borders

I have a winform app that we use in house. It has many individual controls on each of it's 25 "pages"(usercontrols). Our user base prefers very technicolor apps...they want a TextBox to be outlined Blue if it is a required field (color should go away if data entered). They want a TextBox to change to outlined Green if data has been changed in it to remind them to save. They want a currently highlighted TextBox to be outlined RedOrange.
I have been trying to come at this from many different angles (some of you have probably seen similar posts by me lately). Non of them work... So one way I KNOW will work is to register the paint event for every control and check for a "required" tag for the required portion. The OnFocus for the current field portion and finally the Validate event for the data changed portion.
I know this is not the best way or at least I STRONGLY suspect it isn't but I am out of time, nearly, and nearing my point of frustration. That being said, will that DESTROY my app's responsiveness? Is there a better way? Can I override the base control to color on different premises so that I don't have to go to each of the 100+ controls?
Any idea would be welcome because I am between my stupid Paint_Event idea and rewriting all the controls in WPF... :)
I will be rewarding a solution that works for me and that I can implement shortly with a Bounty.
I am so sick of colors...
Here is my attempt based on suggestions.
public class MyTextBox : TextBox
{
private bool _isRequired;
public bool isRequired
{
get
{
return _isRequired;
}
set
{
_isRequired = value;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (isRequired && base.Text.Equals(string.Empty))
{
HighlightControl(e.Graphics);
}
}
private void HighlightControl(Graphics graphics)
{
ControlPaint.DrawBorder(
graphics,
this.ClientRectangle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle);
}
}
I don't know the particulars of your app, but you could derive your own control from the base TextBox and let it handle much of this for you. Some thoughts:
Give it a bool Required property and some internal logic to color accordingly.
Have the textbox respond to its own
events - when text is entered, it can
do the right thing - change colors or
whatever is appropriate.
Provide your derived control with
properties to set the colors that get
used for each condition, then you can
switch them easily when the users
decide they want pink rather than
green.
You can utilize the focus events to "know" whether your TextBox (this is the one control you mentioned, so I'll assume this is the main control used here) has focus or lost it and the text change events can be used to drive all the color changes to the control.
You can certainly wire up all the
text boxes to control the
Apply/OK/whatever buttons to
determine if the buttons should be
enabled, assuming you have an Apply button or something like that which stores the data on click. There are a number of ways to communicate this. It's easy enough to iterate through the controls and ask their state.
Seems like this would work just fine.
What have you tried? You didn't really mention what you'd tried that didn't work.
You've got a problem, TextBox is, erm, special. Windows Forms leaves all painting to the native Windows EDITBOX control, the Paint event won't be raised. That can be fixed by setting the UserPaint control style to true:
using System;
using System.Drawing;
using System.Windows.Forms;
class MyTextBox : TextBox {
public MyTextBox() {
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
// Paint something
//...
}
}
Copy and paste this into a new class, compile and drop the new control from the top of the toolbox. Try it out, you'll be quite disappointed. What you see is the result of close to 20 years of appcompat hacks on a control that dates back to Windows version 2. One of the grave crimes that EDITBOX commits is painting itself without generating a WM_PAINT message. That was important way back when Windows had to run on a 386SUX, keeping it compatible with old programs prevented Microsoft from fixing its behavior.
No happy answers here, you'll have to give up on the idea of customizing the border. What you can do is give the control a distinct BackColor when it has the focus. For example:
class MyTextBox : TextBox {
Color mBackColor;
protected override void OnEnter(EventArgs e) {
mBackColor = base.BackColor;
base.BackColor = Color.AliceBlue;
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
base.BackColor = mBackColor;
base.OnLeave(e);
}
}
You can inherit from base control classes and add your own drawing logic. That won't be very expensive performance-wise, but, if your app is of significant size, you'll have to replace each occurence of standard TextBox with your own implementation.

Categories