HotDog's Blog

Hotdog (Robert Verpalen) about C# and vb.net

This blog hosted by:
http://blogs.vbcity.com      
  Home :: Syndication  :: Login

AprMay 2008Jun
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Articles

Archives

Topics

CONTACT

Fun but useful linkies

General

VS 2005

Wolfenstein ET

Code CopyHideScrollFull
#define IncludeDesignTimeSupport

using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Drawing;
using
System.Text;
using
System.Windows.Forms;


//Legal mumbo jumbo:
//(c) 2006 R.Verpalen, Subro Software
//the control and code can be freely used, but the source may only be distributed through a site of the creator
//at this time, that means blogs.vbcity.com/hotdog
//That also means personal alterations are for your own use only ;-)

namespace
Subro.Controls
{
/// <summary>
///
Continuous control: drag any control or number of controls onto it's design surface, attach
///
a bindingsource and a continous 'subform' is the result
///
</summary>
///
<remarks>
///
Needed references:
///
     the default windows forms: System,System.Drawing,System.Windows.Forms
///
     for design time functionality: System.Design
///
Although the class can't be designed directly (due to the way
///
visual studio handles the designer creation), but inheriting classes
///
and instances dropped onto another designer support full design
///
time functionality
///
</remarks>
///
#if IncludeDesignTimeSupport
[Designer(typeof(ContinuousControlDesigner))]
[Designer(typeof(ContinuousControlDocumentDesigner), typeof(System.ComponentModel.Design.IRootDesigner))]
#endif
[DefaultProperty("BindingSource")]
public
partial class ContinuousControl : Panel, ISupportInitialize
{
#region constructor
Panel scrollpanel = new Panel();
public ContinuousControl()
{
Init();
}
void Init()
{
this.Name = "ContinuousControl";
this
.MinimumSize = new Size(100, 24);
base
.BorderStyle = DefaultBorderStyle;
scrollpanel.AutoScroll = true;
scrollpanel.Dock = DockStyle.Fill;
scrollpanel.BackColor = Color.Gray;
Controls.Add(scrollpanel);
mainpanel = new MainPanel(this);
instance = new ControlInstance(this);
this
.NavigatorStyle = GetDefaultNavigatorStyle();
valfailedaction = GetDefaultValidationFailedAction();
}

#endregion
#region designer support
//this region contains the small designer part that's always
//included for easy compilation

//the actual design time support is in the partial class further down

//and can be omitted if wanted for the final release.   
//properties windows category constants
protected
const string CategoryPrefix = " ";
protected
const string DataCategory = CategoryPrefix + "Data";
protected
const string ItemCategory = CategoryPrefix + "Item settings";
protected
const string NavigatorCategory = CategoryPrefix + "Navigator";
protected
const string HeaderCategory = CategoryPrefix + "Header";
protected
const string BehaviorCategory = CategoryPrefix + "Behavior";

#if
IncludeDesignTimeSupport
/// <summary>
///
Only used for design time functionality for inheritors
///
</summary>
protected
IComponent _Instance;
#endif
#endregion
#region supporting controls
ControlInstance instance;
/// <summary>
///
Direct access to the controls of the main record instance.
///
Controls added in design time are also serialized through this property
///
</summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public
ControlCollection InstanceControls
{
get { return instance.Controls; }
}

#if
IncludeDesignTimeSupport
[Designer(typeof(InstanceDesigner))]
[System.ComponentModel.Design.Serialization.DesignerSerializer(
typeof(System.ComponentModel.Design.Serialization.CodeDomSerializer),
typeof
(System.ComponentModel.Design.Serialization.CodeDomSerializer))] //this serializer is attached to make sure the inheriting classes will not serialize properties of the protected instance
#endif
class ControlInstance : Control
{
public readonly ContinuousControl owner;
public
ControlInstance(ContinuousControl Owner)
{
BackColor = Owner.BackColor;
Owner.mainpanel.Controls.Add(this);
this
.owner = Owner;
}
Brush nonfocusbrush;
public
override Color BackColor
{
get
{
return base.BackColor;
}
set

{
base.BackColor = value;
nonfocusbrush = new System.Drawing.Drawing2D.HatchBrush(
System.Drawing.Drawing2D.HatchStyle.Percent05 | System.Drawing.Drawing2D.HatchStyle.LightUpwardDiagonal,
ControlPaint.Light(value),
value);
}
}
public bool ChildPaint;
/*
protected override void OnPaintBackground(PaintEventArgs pevent)
{
if (ChildPaint && !DesignMode)
pevent.Graphics.FillRectangle(nonfocusbrush, ClientRectangle);
else
{
base.OnPaintBackground(pevent);                    
//ControlPaint.DrawBorder(pevent.Graphics, ClientRectangle, Color.Navy, ButtonBorderStyle.Solid);
}
}*/
public ContinuousControl Owner
{
get { return owner; }
}
protected override Size DefaultSize
{
get
{
return owner == null ? Size.Empty : owner.ItemSize;
}
}
object Current
{
get { return owner.source.Current; }
}
protected override void OnLayout(LayoutEventArgs levent)
{
if (!owner.IsInitializing)
Reset();
base.OnLayout(levent);
}
void Reset()
{
owner.ResetItemSize();
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
Owner.mainpanel.CheckDragStart();
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
Owner.mainpanel.CheckDragStart();
base.OnMouseMove(e);
}

internal bool Validate()
{
owner.source.EndEdit();
Focus();
if
(!Focused)
{
bool AllowContinue;
owner.OnRecordValidationFailed(out AllowContinue);
return
AllowContinue;
}
return
true;
}
internal void CancelCurrentEdit()
{
owner.source.CurrencyManager.CancelCurrentEdit();
}
}
bool suspendlocationchange;
///
<summary>
///
Sets the focus control to the proper position.
///
This procedure is executed when the <see cref="BindingSource"/>'s
///
position is changes or when a layout property is changed
///
</summary>
void
SetInstanceLocation()
{
if (IsInitializing) return;
#if IncludeDesignTimeSupport
if (this.DesignMode)
{
SetDesignTimeInstanceSize();
}
else
#endif
if (instance != null && !suspendlocationchange)
{
SuspendLayout();
InvalidateSelectionArea(instance.Bounds);
bool
vis = SelectedIndex != -1;
instance.Visible = vis;
if
(vis)
{
instance.Bounds = GetNonPaddedItemBounds(SelectedIndex);
scrollpanel.ScrollControlIntoView(instance);
}
InvalidateSelectionArea(instance.Bounds);
ResumeLayout();
}
}


MainPanel mainpanel;
class MainPanel : ContainerControl
{
public readonly ContinuousControl Owner;
public
MainPanel(ContinuousControl Owner)
{
this.Owner = Owner;
Size = Size.Empty;
Height = 0;
Dock = DockStyle.Top;
SetStyle(
ControlStyles.OptimizedDoubleBuffer
| ControlStyles.UserPaint
| ControlStyles.AllPaintingInWmPaint
, true);
Owner.scrollpanel.Controls.Add(this);
}
protected override bool ProcessTabKey(bool forward)
{
if (!Owner.handletabs)
return base.ProcessTabKey(forward);
return ProccessTabKey(forward, ActiveControl);
}
bool ProccessTabKey(bool forward, Control current)
{
bool wrap = forward ? Owner.SelectedIndex < Owner.Count - 1 : Owner.SelectedIndex > 0;
bool
res = SelectNextControl(current, forward, true, true, false);
if (!res && wrap)
{
if (forward)
Owner.SelectedIndex++;
else
Owner.SelectedIndex--;
return SelectNextControl(null, forward, true, true, false);
}
return
res;
}
#region
Paint
public new void Paint(Graphics g)
{
if (Owner.ItemSize.Height == 0)
{
if (Owner.DrawStartInsertButton)
DrawInsertButton(-1, g);
return;
}
Point
p = Owner.scrollpanel.AutoScrollPosition;
p.X *= -1;
p.Y *= -1;
int
from = Owner.GetIndex(p);
p.Offset(Parent.Width, Parent.Height);
int
sel = Owner.SelectedIndex;
int
to = Owner.GetIndex(p) + 1;
if
(to > Owner.Count && !Owner.DesignMode) to = Owner.Count;
for (int i = from; i < to; i++)
{
if (i == -1)
{
//first insert button
DrawInsertButton(i, g);
continue
;
}
Rectangle bounds = Owner.GetNonPaddedItemBounds(i);

bool selected = i == sel;
if (!Owner.DesignMode)
{
if (selected ||
(Owner.multiselect && Owner.GetItem(i).SelectedVersion == Owner.selectionversion))
{
selected = true;
g.FillRectangle(SelectionBrush, Owner.GetSelectionBounds(bounds));
}
if (i != sel)
{
Bitmap bmp = Owner.GetBitmap(i);
g.DrawImage(bmp, bounds.Location);
}
}
else
if (i > 0)
{
g.DrawRectangle(Pens.Black, bounds);
}
//select buttons
if
(Owner.showselectbuttons)
{
DrawSelectButton(bounds, g, selected);
}
//insert buttons
if
(Owner.ShowInsertButtons)
{
bool last = i == Owner.Count - 1;
if
((Owner.DrawInsertButtonsBetweenItems && !last)
|| (Owner.DrawEndInsertButton && last))
DrawInsertButton(i, g);
}
//delete button
if
(Owner.ShowDeleteButtonPerItem)
{
DrawDeleteButton(i, g);
}
//drag insert
if
(Owner.DragInsertIndex == i)
{
DrawDragInsert(i, g);
}
}
if (to == Owner.Count && Owner.DragInsertIndex == to)
DrawDragInsert(to, g);
}
void DrawInsertButton(int Index, Graphics g)
{
Rectangle bounds = Owner.GetInsertButtonBounds(Index);
DrawButton(bounds, g, Owner.insertbuttonicon,
InsertButtonFocused == Index, Owner.source != null && !Owner.source.AllowNew, InsertButtonPushed == Index);
}
void DrawSelectButton(Rectangle bounds, Graphics g, bool IsSelected)
{
if (Owner.lefttoright)
{
bounds.Y = 0;
bounds.Height = SelectButtonWidth;
}
else

{
bounds.X = 0;
bounds.Width = SelectButtonWidth;
}
g.DrawRectangle(new Pen(Owner.instance.BackColor), bounds);
if
(IsSelected)
{
g.DrawImage(Owner.SelectedRecordImage,
bounds.X + (bounds.Width - Owner.SelectedRecordImage.Width) / 2,
bounds.Top + (bounds.Height - Owner.SelectedRecordImage.Height) / 2);
}
}
void DrawButton(Rectangle bounds,
Graphics g,
Icon
ic,
bool
IsSelected, bool IsInActive, bool IsPushed)
{
if (IsInActive)
{
ControlPaint.DrawButton(g, bounds, ButtonState.Inactive);
}
else
if (IsSelected)
{
ControlPaint.DrawButton(g, bounds,
IsPushed
? ButtonState.Pushed
: ButtonState.Normal);
}
else
ControlPaint.DrawBorder(g, bounds, Color.Gray, ButtonBorderStyle.Outset);
g.DrawIcon(ic, bounds.X + (bounds.Width - ic.Width) / 2, bounds.Y + (bounds.Height - ic.Height) / 2);
}
void DrawDeleteButton(int Index, Graphics g)
{
Rectangle bounds = Owner.GetDeleteButtonBounds(Index);
DrawButton(bounds, g, Owner.deletebuttonicon,
Index == DeleteButtonFocused,
Owner.source != null && !Owner.source.AllowRemove,
DeleteButtonPushed == DeleteButtonFocused);
}
protected override void OnPaint(PaintEventArgs e)
{
Paint(e.Graphics);
base
.OnPaint(e);
}
public Brush SelectionBrush = new SolidBrush(SystemColors.Highlight);
#endregion
#region DragDrop
public override bool AllowDrop
{
get
{
return base.AllowDrop;
}
set

{
base.AllowDrop = value;
}
}
bool UseDrag
{
get
{
return AllowDrop || Owner.autodrag;
}
}
Point DragStartPoint;
public void CheckDragStart()
{
if (!UseDrag) return;
Point
p = LocalMousePosition;
int
diff = Math.Abs(DragStartPoint.X - p.X)
+ Math.Abs(DragStartPoint.Y - p.Y);
if (diff > 3)
{
Owner.OnDragStart(Owner.GetIndex(DragStartPoint));
DragStartPoint = Point.Empty;
}
}
protected override void OnDragEnter(DragEventArgs e)
{
Owner.OnDragEnter(e);
}
protected override void OnDragOver(DragEventArgs e)
{
Owner.OnDragOver(e);
}
protected override void OnDragLeave(EventArgs e)
{
Owner.OnDragLeave(e);
}

protected override void OnDragDrop(DragEventArgs e)
{
DragStartPoint = Point.Empty;
Owner.OnDragDrop(e);
}
const int DragInsertHeight = 3;
Rectangle GetDragInsertBounds(int Index)
{
Rectangle res = Owner.GetItemBounds(Index);
float
half = DragInsertHeight / 2f;
if
(Index == 0)
half = 0;
else if (Index == Owner.Count)
half = DragInsertHeight;
if (Owner.lefttoright)
{
res.Y = 0;
res.Height = Height;
res.X -= (int)Math.Ceiling(half);
res.Width = DragInsertHeight;
}
else

{
res.X = 0;
res.Width = Width;
res.Y -= (int)Math.Ceiling(half);
res.Height = DragInsertHeight;
}
return
res;
}
void DrawDragInsert(int Index, Graphics g)
{
g.FillRectangle(Brushes.Yellow, GetDragInsertBounds(Index));
}
public void InvalidateDragInsert(int Index)
{
Invalidate(GetDragInsertBounds(Index));
}
#endregion
public void SetSize()
{
int i = Owner.Count;
if
(i == 0)
Size = Size.Empty;
else
{
Rectangle r = Owner.GetItemBounds(i);
int
diff = 0;
if
(Owner.ShowInsertButtons && !Owner.DrawInsertButtonsBetweenItems)
{
if (Owner.DrawStartInsertButton)
diff += InsertButtonHeight;
if (Owner.DrawEndInsertButton)
diff += InsertButtonHeight;
}
Size = new Size(
Owner.lefttoright ? r.Left + diff : r.Right,
Owner.lefttoright ? r.Bottom : r.Top + diff);
}
}

#region buttons
int DeleteButtonFocused = -1;
int
DeleteButtonPushed = -1;
int
? InsertButtonFocused;
int
? InsertButtonPushed;
int
GetDeleteButtonFocused()
{
Point p = LocalMousePosition;
int
index = Owner.GetIndex(p);
if
(Owner.GetDeleteButtonBounds(index).Contains(p))
return index;
return -1;
}
int
? GetInsertButtonFocused()
{
Point p = LocalMousePosition;
int
index = Owner.GetIndex(p);
if
(Owner.GetInsertButtonBounds(index).Contains(p))
return index;
return null;
}
Point LocalMousePosition
{
get
{
return PointToClient(Control.MousePosition);
}
}
bool CheckButtonFocus()
{
if (Owner.ShowDeleteButtonPerItem)
{
int i = GetDeleteButtonFocused();
if
(i != DeleteButtonFocused)
{
InvalidateDeleteButton();
DeleteButtonFocused = i;
InvalidateDeleteButton();
}
if
(i != -1) return true;
}
if (Owner.ShowInsertButtons)
{
int? i = GetInsertButtonFocused();
if
(i != InsertButtonFocused)
{
InvalidateInsertButton();
InsertButtonFocused = i;
InvalidateInsertButton();
}
if
(i != null) return true;
}
return
false;
}
void InvalidateDeleteButton()
{
if (DeleteButtonFocused != -1)
Invalidate(Owner.GetDeleteButtonBounds(DeleteButtonFocused));
}
void InvalidateInsertButton()
{
if (InsertButtonFocused != null)
Invalidate(Owner.GetInsertButtonBounds(InsertButtonFocused.Value));
}


#endregion
#region Mouse events
protected
override void OnMouseMove(MouseEventArgs e)
{
if (!DragStartPoint.IsEmpty)
{
CheckDragStart();
}
CheckButtonFocus();
base
.OnMouseMove(e);
}
protected override void OnMouseLeave(EventArgs e)
{
if (Owner.ShowDeleteButtonPerItem)
CheckButtonFocus();
base.OnMouseLeave(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DeleteButtonPushed = DeleteButtonFocused;
InsertButtonPushed = InsertButtonFocused;
if
(DeleteButtonFocused != -1)
{
InvalidateDeleteButton();
}
else
if (InsertButtonFocused != null)
InvalidateInsertButton();
else
{
if (UseDrag)
DragStartPoint = LocalMousePosition;
SelectPointed();
}
}
base
.OnMouseDown(e);
}


protected override void OnMouseUp(MouseEventArgs e)
{
if (DeleteButtonPushed != -1 && DeleteButtonPushed == DeleteButtonFocused)
{
Owner.source.RemoveAt(DeleteButtonPushed);
}
if
(InsertButtonPushed != null && InsertButtonFocused == InsertButtonPushed)
{
//insert
Owner.OnInsertItem(InsertButtonPushed.Value + 1);
}
DeleteButtonPushed = -1;
InsertButtonPushed = null;
DragStartPoint = Point.Empty;
base
.OnMouseUp(e);
}
#endregion
#region selection
bool IsMultiSelectClick
{
get
{
if (Owner.multiselect)
//return (ModifierKeys & (Keys.Control | Keys.Shift)) > 0;
return
ModifierKeys == Keys.Control;
return false;
}
}
void SelectPointed()
{
Point p = LocalMousePosition;
int
index = Owner.GetIndex(p);

if (IsMultiSelectClick)
{
Owner.SwitchSelect(index);
return
;
}
Owner.SelectedIndex = index;
Owner.instance.Focus();
Rectangle r = Owner.GetItemBounds(index);
p.X -= r.X;
p.Y -= r.Y;
Control
c = GetChild(Owner.instance, Control.MousePosition);
if
(c != null)
{
InvokeOnClick(c, EventArgs.Empty);
c.Focus();
}
}
Control GetChild(Control c, Point p)
{
Control child = c.GetChildAtPoint(c.PointToClient(p));
if
(child == null) return c;
return
GetChild(child, p);
}
#endregion
}
#endregion
#region item collection
List<Item> items = new List<Item>();
class Item
{
public Bitmap Bitmap;
public
int SelectedVersion;
public
void Clear()
{
Bitmap = null;
}
}
void ResetIndex(int Index)
{
if (IsItemCreated(Index))
{
if (Index == SelectedIndex)
{
items[Index].Bitmap = createBitmap();
}
else

{
items[Index].Clear();
mainpanel.Invalidate(GetItemBounds(Index));
}
}
}
bool IsItemCreated(int Index)
{
return Index < items.Count;
}
Item GetItem(int Index)
{
while (items.Count <= Index)
items.Add(new Item());
return items[Index];
}

void ResetItems()
{
items.Clear();
}
#endregion
#region bitmaps


Bitmap GetBitmap(int Index)
{
Item res = GetItem(Index);
if
(res.Bitmap == null)
res.Bitmap = createBitmap(Index);
else if (!VariableSize && res.Bitmap.Size != ItemSize)
{
res.Bitmap = null;
return
GetBitmap(Index);
}
return
res.Bitmap;
}
Bitmap createBitmap(int Index)
{
if (source == null) return null;
int pos = source.Position;
suspendlocationchange = true;
SuspendLayout();
try

{
source.Position = Index;
return
createBitmap();
}
finally

{
source.Position = pos;
suspendlocationchange = false;
ResumeLayout(false);
}
}
Bitmap
createBitmap()
{
try
{
Bitmap bmp = new Bitmap(instance.Width, instance.Height);
instance.ChildPaint = true;
instance.DrawToBitmap(bmp, new Rectangle(Point.Empty, instance.Size));
return
bmp;
}
catch
(Exception ex)
{
return GetErrorBitmap(SelectedIndex, ex);
}
finally

{
instance.ChildPaint = false;
}
}
protected override void OnEnabledChanged(EventArgs e)
{
base.OnEnabledChanged(e);
for
(int i = 0; i < items.Count; i++)
{
items[i].Clear();
}
mainpanel.Invalidate();
}

/*
Bitmap GetEmptyBitmap()
{
Size size = ItemSize;
return new Bitmap(size.Width, size.Height);
}*/
private Bitmap GetErrorBitmap(int Index, Exception ex)
{
Rectangle r = GetItemBounds(Index);
Bitmap
bmp = new Bitmap(r.Width, r.Height);
Graphics
g = Graphics.FromImage(bmp);
Icon
icon = SystemIcons.Error;
g.DrawIcon(icon, 0, 0);
return
bmp;
}

[System.Runtime.InteropServices.DllImport("shell32.dll")]
extern
static IntPtr ExtractIcon(int hInst, string lpszExeFileName, int nIconIndex);
public
static Icon GetIcon(int index)
{
return GetIcon("shell32.dll", index);
}
public
static Icon GetIcon(string dll, int index)
{
IntPtr handle = ExtractIcon(0, dll, index);
Icon
ic = Icon.FromHandle(handle);
Bitmap
bmp = new Bitmap(16, 16);
Graphics
.FromImage(bmp).DrawIcon(ic, new Rectangle(0, 0, bmp.Width, bmp.Height));
return
Icon.FromHandle(bmp.GetHicon());
}
public static Bitmap GetTriangleBitmap(bool lefttoright, int width, int height, Brush FillColor)
{
Bitmap res = new Bitmap(width, height);
Graphics
g = Graphics.FromImage(res);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
if
(lefttoright)
{
gp.AddLine(0, 0, width / 2, height);
gp.AddLine(width / 2, height, width, 0);
gp.AddLine(width, 0, 0, 0);
}
else

{
gp.AddLine(0, 0, width, height / 2);
gp.AddLine(width, height / 2, 0, height);
gp.AddLine(0, height, 0, 0);
}
g.FillPath(FillColor, gp);
g.DrawPath(Pens.Black, gp);
return res;
}

#endregion
#region scrolling
[DefaultValue(true)]
public
new bool AutoScroll
{
get { return scrollpanel.AutoScroll; }
set
{ scrollpanel.AutoScroll = value; }
}
[DefaultValue(false)]
public
override bool AutoSize
{
get
{
return base.AutoSize;
}
set

{
if (value == AutoSize) return;
if
(!DesignMode)
{
if (value)
{
scrollpanel.Dock = DockStyle.Fill;
}
else

{
scrollpanel.Dock = DockStyle.Top;
}
}
scrollpanel.AutoSize = value;
base
.AutoSize = value;
}
}

#endregion
#region source
private BindingSource source;
[Category(DataCategory)]
[DefaultValue(null)]
public
BindingSource BindingSource
{
get { return source; }
set

{
if (source != null)
{
source.ListChanged -= new ListChangedEventHandler(source_ListChanged);
source.PositionChanged -= new EventHandler(source_PositionChanged);
}
source = value;
ResetList();
if
(source != null)
{
source.ListChanged += new ListChangedEventHandler(source_ListChanged);
source.PositionChanged += new EventHandler(source_PositionChanged);
}
if
(navigator != null)
navigator.BindingSource = source;
OnBindingSourceChanged();
}
}
public event EventHandler BindingSourceChanged;
protected
virtual void OnBindingSourceChanged()
{
if (BindingSourceChanged != null)
BindingSourceChanged(this, EventArgs.Empty);
}
int previousposition = -1;
void
source_PositionChanged(object sender, EventArgs e)
{
if (suspendlocationchange) return;

if (multiselect)
{
selectionversion++;
if
(previousposition != -1 && ModifierKeys == Keys.Shift)
{
int pos = source.Position;
int
from = Math.Min(pos, previousposition), to = Math.Max(pos, previousposition);
for
(int i = from; i <= to; i++)
{
GetItem(i).SelectedVersion = selectionversion;
}
}
if (items.Count > 200)
mainpanel.Invalidate();
else
{
InvalidateSelected(selectionversion - 1);
InvalidateSelected(selectionversion);
}
}
SetInstanceLocation();
previousposition = source.Position;
}

[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
int SelectedIndex
{
get
{
if (source == null) return -1;
return
source.Position;
}
set

{
if (source != null)
{
Control c = GetActiveControl();
if
(!instance.Validate())
{
return;
}
ResetIndex(SelectedIndex);
source.Position = value;
if
(c != null)
{
c.Select();
}
}
}
}
Control GetActiveControl()
{
Form f = FindForm();
if
(f == null) return null;
return
GetActiveControl(f);
}
Control
GetActiveControl(ContainerControl cc)
{
Control c = cc.ActiveControl;
if
(c is ContainerControl)
return GetActiveControl(c as ContainerControl);
return c;
}
[Browsable(false)]
public
int Count
{
get
{
if (source == null) return 0;
return
source.Count;
}
}
void RefreshItems()
{
if (DesignMode || IsInitializing) return;
ResetItems();
InvalidateMainPanel();
}
public void ResetList()
{
if (DesignMode || IsInitializing) return;
previousposition = -1;
RefreshItems();
OnResetList();
}
protected virtual void OnResetList()
{
}
bool IsBindingSuspended
{
get
{
return source != null && source.IsBindingSuspended;
}
}
int editing;
public
void BeginUpdate()
{
editing++;
}
public void EndUpdate()
{
if (--editing <= 0)
{
editing = 0;
if
(needreset)
{
needreset = false;
ResetList();
}
}
}
bool
needreset;
void source_ListChanged(object sender, ListChangedEventArgs e)
{
if (editing > 0)
{
needreset = true;
return
;
}
if (e.ListChangedType == ListChangedType.ItemAdded)
{
if (IsItemCreated(e.NewIndex))
items.Insert(e.NewIndex, new Item());
mainpanel.SetSize();
}
else
if (e.ListChangedType == ListChangedType.ItemDeleted)
{
if (e.NewIndex < items.Count)
{
items.RemoveAt(e.NewIndex);
mainpanel.Invalidate();
mainpanel.SetSize();
}
else
if (items.Count == 0)
SetInstanceLocation();
}
else
if (e.ListChangedType == ListChangedType.ItemMoved)
{
ResetIndex(e.OldIndex);
ResetIndex(e.NewIndex);
}
else
if (e.ListChangedType == ListChangedType.Reset)
{
ResetList();
}
else
if (e.ListChangedType == ListChangedType.ItemChanged)
{
ResetIndex(e.NewIndex);
}
}
#endregion
#region item sizing
Size? itemsize;
[Category(ItemCategory)]
public
Size ItemSize
{
get
{
if (itemsize == null)
{
itemsize = GetItemSize();
if
(instance != null && !DesignMode)
instance.Size = itemsize.Value;
}
return
itemsize.Value;
}
set

{
if (value.IsEmpty)
itemsize = null;
else
itemsize = value;
}
}
bool
ShouldSerializeItemSize()
{
return FixedItemSize;// itemsize != null && !GetItemBounds().Equals(itemsize.Value);
}
void
ResetItemSize()
{
if (FixedItemSize) return;
itemsize = null;
if
(VariableSize && !DesignMode && SelectedIndex > -1)
ResetIndex(SelectedIndex);
//sizewithbounds = null;
InvalidateMainPanel();
}
[Category(ItemCategory)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
bool FixedItemSize
{
get { return itemsizemode == ItemSizeMode.Fixed; }
set

{
if (value == FixedItemSize) return;
if
(value)
ItemSizeMode = ItemSizeMode.Fixed;
else
ItemSizeMode = ItemSizeMode.Automatic;
}
}
static Padding DefaultItemPadding = new Padding(1);
private
Padding itemPadding = DefaultItemPadding;
[Category(ItemCategory)]
public
Padding ItemPadding
{
get { return itemPadding; }
set

{
itemPadding = value;
if
(!IsInitializing)
SetInstanceLocation();
else if (DesignMode)
Invalidate();
else
mainpanel.Invalidate();
}
}
bool
ShouldSerializeItemPadding()
{
return itemPadding != DefaultItemPadding;
}
void
ResetItemPadding()
{
itemPadding = DefaultItemPadding;
}
/*
private Size? sizewithbounds;
[Category(ItemCategory)]
public Size ItemSizeWithPadding
{
get
{
if (sizewithbounds == null)
{
sizewithbounds = GetItemSizeWithBounds();
}
return sizewithbounds.Value;
}
}
*/
[Browsable(false)]
public
bool VariableSize
{
get { return itemsizemode == ItemSizeMode.Variable || itemsizemode == ItemSizeMode.VariableUserSizable; }
}
private ItemSizeMode itemsizemode;
[Category(ItemCategory)]
[DefaultValue(ItemSizeMode.Automatic)]
public
ItemSizeMode ItemSizeMode
{
get { return itemsizemode; }
set
{ itemsizemode = value; }
}

Size GetItemSizeWithBounds()
{
Size size = ItemSize;
if
(size.IsEmpty) return size;
size.Width += itemPadding.Horizontal;
size.Height += itemPadding.Vertical;
return
size;
}
Size GetItemSize()
{
//if (controls.Count == 0) return Size.Empty;
Size
size = new Size();
foreach
(Control c in instance.Controls)
{
size.Width = Math.Max(size.Width, c.Right);
size.Height = Math.Max(size.Height, c.Bottom);
}
return
size;
}
int GetItemTop(int Index)
{
if (lefttoright)
{
if (showselectbuttons) return SelectButtonWidth;
return
0;
}
int res;
if
(VariableSize && !DesignMode)
{
if (Index > 0)
{
res = AddReoccuringHeight(GetBitmap(--Index).Height)
+ GetItemTop(Index);
}
else
res = 0;
}
else
res = GetItemHeight() * Index;
if (DrawStartInsertButton)
res += InsertButtonHeight;
return res;
}
int GetItemLeft(int Index)
{
int res = 0;
if
(!lefttoright)
{
if (showselectbuttons)
res += SelectButtonWidth;
return res;
}
if (VariableSize && !DesignMode)
{
if (Index > 0)
{
res = AddReoccuringWidth(GetBitmap(--Index).Width)
+ GetItemLeft(Index);
}
}
else

{
res += GetItemWidth();
res *= Index;
}
if
(DrawStartInsertButton)
res += InsertButtonHeight;

return res;
}
int AddReoccuringWidth(int w)
{
w += itemPadding.Horizontal;
if
(ShowDeleteButtonPerItem) w += DeleteButtonWidth;
if
(lefttoright && DrawInsertButtonsBetweenItems)
{
w += InsertButtonHeight;
}
return
w;
}
int GetItemWidth()
{
return AddReoccuringWidth(ItemSize.Width);
}
int AddReoccuringHeight(int h)
{
h += itemPadding.Vertical;
if
(!lefttoright && DrawInsertButtonsBetweenItems)
{
h += InsertButtonHeight;
}
return
h;
}
int GetItemHeight()
{
return AddReoccuringHeight(ItemSize.Height);
}
/// <summary>
///
Gets which item is at the specified point of the mainpanel
///
</summary>
///
<param name="p"></param>
///
<returns></returns>
int
GetIndex(Point p)
{
int t, xy;
if
(lefttoright)
{
t = GetItemWidth();
xy = p.X;
}
else

{
t = GetItemHeight();
xy = p.Y;
}
if
(ShowInsertButtons && (insertbuttonstyle & InsertButtonStyles.BeginOnly) > 0)
{
xy -= InsertButtonHeight;
}
if
(xy < 0) return -1;
return
xy / t;
}
Size PadSize(Size size)
{
size.Width += itemPadding.Horizontal;
size.Height += itemPadding.Vertical;
return
size;
}
Rectangle GetItemBounds(int Index)
{
return GetItemBounds(Index, 0, 0, true);
}
Rectangle GetItemBounds(int Index, int LeftOffset, int TopOffset, bool padded)
{
Size size;
if
(VariableSize && Index > -1 && GetItem(Index).Bitmap != null)
size = GetItem(Index).Bitmap.Size;
else
size = ItemSize;
if (padded) size = PadSize(size);
return new Rectangle(
GetItemLeft(Index) + LeftOffset,
GetItemTop(Index) + TopOffset
, size.Width
, size.Height);
}
Rectangle
GetNonPaddedItemBounds(int Index)
{
return GetItemBounds(Index, ItemPadding.Left, ItemPadding.Top, false);
}
protected override Size DefaultSize
{
get
{
return new Size(100, 150);
}
}
#endregion
#region Item validation
protected virtual void OnRecordValidationFailed(out bool AllowContinue)
{
if (RecordValidationFailed != null)
{
HandledEventArgs e = new HandledEventArgs(false);
RecordValidationFailed(this, e);
if
(e.Handled)
{
AllowContinue = true;
return
;
}
}
switch
(valfailedaction)
{
case ValidationFailedActions.AskUser:
AllowContinue = MessageBox.Show("The current input does not validate correctly. If you continue to another record the changes will be lost. Do you wish to continue?"
, null, MessageBoxButtons.YesNoCancel) == DialogResult.Yes;
break;
case ValidationFailedActions.DiscardChanges:
AllowContinue = true;
break
;
default:
AllowContinue = false;
break
;
}
}
public
event HandledEventHandler RecordValidationFailed;
public enum ValidationFailedActions
{
AskUser, DiscardChanges, BlockRecordChange
}
private ValidationFailedActions valfailedaction;
[Category(BehaviorCategory)]
public
ValidationFailedActions ValidationFailedAction
{
get { return valfailedaction; }
set
{ valfailedaction = value; }
}
bool
ShouldSerializeValidationFailedAction()
{
return valfailedaction != GetDefaultValidationFailedAction();
}
protected virtual ValidationFailedActions GetDefaultValidationFailedAction()
{
return ValidationFailedActions.BlockRecordChange;
}
#endregion
#region Key handling
bool In(Keys value, params Keys[] keys)
{
return Array.IndexOf<Keys>(keys, value) != -1;
}
protected override bool IsInputKey(Keys keyData)
{
return In(keyData, Keys.Up, Keys.Down, Keys.PageDown, Keys.PageUp, Keys.Escape)
|| base.IsInputKey(keyData);
}
private
bool handletabs = false;
[DefaultValue(false)]
[Description("If true, all records are walked through when tab is pressed before the control loses focus")]
public
bool HandleTabs
{
get { return handletabs; }
set
{ handletabs = value; }
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (source != null)
{
if (keyData == Keys.Up)
{
if (!lefttoright)
SelectedIndex--;
}
else
if (keyData == Keys.Down)
{
if (!lefttoright)
SelectedIndex++;
}
else
if (keyData == Keys.Left)
{
if (lefttoright)
SelectedIndex--;
}
else
if (keyData == Keys.Right)
{
if (lefttoright)
SelectedIndex++;
}
else
if (keyData == Keys.PageUp)
SelectedIndex -= CountPerPage;
else if (keyData == Keys.PageDown)
SelectedIndex += CountPerPage;
else if (keyData == Keys.Escape)
instance.CancelCurrentEdit();
}
return
base.ProcessCmdKey(ref msg, keyData);
}

int CountPerPage
{
get
{
return (int)Math.Ceiling((double)scrollpanel.Height / ItemSize.Height);
}
}
#endregion
#region additional properties
const BorderStyle DefaultBorderStyle = BorderStyle.Fixed3D;
[DefaultValue(DefaultBorderStyle)]
public
new BorderStyle BorderStyle
{
get { return base.BorderStyle; }
set
{ base.BorderStyle = value; }
}
#endregion
#region Navigator
BindingNavigator navigator;
public enum NavigatorStyles
{
None,
Simple,
Extended
}
private NavigatorStyles navstyle;
[Category(NavigatorCategory)]
public
NavigatorStyles NavigatorStyle
{
get { return navstyle; }
set

{
if (navstyle == value) return;
ShowNavigator = value != NavigatorStyles.None;
if
(ShowNavigator)
ShowFullNavigatorOptions = value == NavigatorStyles.Extended;
}
}
bool
ShouldSerializeNavigatorStyle()
{
return navstyle != GetDefaultNavigatorStyle();
}
protected virtual NavigatorStyles GetDefaultNavigatorStyle()
{
return NavigatorStyles.None;
}


[Category(NavigatorCategory)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
bool ShowNavigator
{
get
{
return navigator != null;
}
set

{
if (value == ShowNavigator) return;
if
(value)
{
navigator = new BindingNavigator(source);
navigator.DeleteItem.Click += new EventHandler(DeleteItem_Click);
navigator.GripStyle = ToolStripGripStyle.Hidden;
SetNavigatormode(false);
navigator.Width = navigator.Height = 20;
//if (!DesignMode)
Controls.Add(navigator);
navstyle = NavigatorStyles.Simple;
}
else

{
navigator.Dispose();
navigator = null;
navstyle = NavigatorStyles.None;
}
}
}
bool
ShouldSerializeShowNavigator()
{
return GetDefaultNavigatorStyle() != NavigatorStyles.None;
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
BindingNavigator BindingNavigator
{
get { return navigator; }
}
bool showfulloptions;
[Category(NavigatorCategory)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
bool ShowFullNavigatorOptions
{
get { return showfulloptions; }
set

{
if (showfulloptions == value) return;
if
(!value && navigator == null)
return;
SetNavigatormode(value);
navstyle = value ? NavigatorStyles.Extended : NavigatorStyles.Simple;
}
}
bool
ShouldSerializeShowFullNavigatorOptions()
{
return (GetDefaultNavigatorStyle() == NavigatorStyles.Extended)
!= showfulloptions;
}
private void SetNavigatormode(bool Full)
{
ShowNavigator = true;
showfulloptions = Full;
foreach
(ToolStripItem it in navigator.Items)
{
if (it != navigator.AddNewItem && it != navigator.DeleteItem)
it.Visible = Full;
}
if
(!dockmanualset)
navigator.Dock = GetDefaultNavigatorDock();
}


DockStyle GetDefaultNavigatorDock()
{
if (ShowFullNavigatorOptions) return DockStyle.Bottom;
return
DockStyle.Left;
}

void DeleteItem_Click(object sender, EventArgs e)
{
DeleteItems(GetSelectedItems(selectionversion));
}
bool
dockmanualset;
[Category(NavigatorCategory)]
public
DockStyle NavigatorLocation
{
get
{
if (!ShowNavigator) return DockStyle.Left;
return
navigator.Dock;
}
set

{
ShowNavigator = value != DockStyle.None;
if
(!ShowNavigator) return;
if
(value == DockStyle.Fill)
value = GetDefaultNavigatorDock();
navigator.Dock = value;
dockmanualset = ShouldSerializeNavigatorLocation();
}
}
bool
ShouldSerializeNavigatorLocation()
{
return navigator != null && NavigatorLocation != GetDefaultNavigatorDock();
}

#endregion
#region Delete button
[DefaultValue(false)]
[Category(ItemCategory)]
public
bool ShowDeleteButtonPerItem
{
get { return deletebuttonicon != null; }
set

{
if (ShowDeleteButtonPerItem == value) return;
if
(value)
DeleteButtonIcon = GetDeleteButtonImage();
else
DeleteButtonIcon = null;
InvalidateMainPanel();
}
}
void InvalidateMainPanel()
{
#if IncludeDesignTimeSupport
if (DesignMode)
{
SetDesignTimeInstanceSize();
mainpanel.Invalidate();
}
else
#endif
if (!IsInitializing)
{
mainpanel.SetSize();
SetInstanceLocation();
mainpanel.Invalidate();
}
}
private Icon deletebuttonicon;
[Category(ItemCategory)]
public
Icon DeleteButtonIcon
{
get { return deletebuttonicon; }
set

{
deletebuttonicon = value;
mainpanel.Invalidate();
}
}
bool
ShouldSerializeDeleteButtonIcon()
{
return deletebuttonicon != null && deletebuttonicon != DefaultDeleteButtonImage;
}
public static Icon DefaultDeleteButtonImage;
static Icon GetDeleteButtonImage()
{
if (DefaultDeleteButtonImage == null)
DefaultDeleteButtonImage = GetIcon(131);
return DefaultDeleteButtonImage;
}
const int DeleteButtonWidth = 16;
Rectangle
GetDeleteButtonBounds(int Index)
{
Rectangle res = new Rectangle(
GetItemLeft(Index) + ItemSize.Width + itemPadding.Left + 1,
GetItemTop(Index) + itemPadding.Top,
DeleteButtonWidth, DeleteButtonWidth);
if (lefttoright && DrawInsertButtonsBetweenItems)
res.X += InsertButtonHeight;
return res;
}
#endregion
#region Insert buttons
public enum InsertButtonStyles
{
None,
BeginOnly = 1,
EndOnly = 2,
AfterEachItem = 4 | EndOnly,
BeforeEachItem = 8 | BeginOnly,
BeforeAndAfterEachItem = AfterEachItem | BeforeEachItem
}
private InsertButtonStyles insertbuttonstyle;
[DefaultValue(InsertButtonStyles.None)]
[Category(ItemCategory)]
public
InsertButtonStyles InsertButtonStyle
{
get { return insertbuttonstyle; }
set

{
if (insertbuttonstyle == value) return;
insertbuttonstyle = value;
ShowInsertButtons = value != InsertButtonStyles.None;
InvalidateMainPanel();
}
}
bool DrawInsertButtonsBetweenItems
{
get
{
return ShowInsertButtons && (insertbuttonstyle & InsertButtonStyles.BeforeAndAfterEachItem) > InsertButtonStyles.EndOnly;
}
}
bool DrawStartInsertButton
{
get
{
return ShowInsertButtons && (insertbuttonstyle & InsertButtonStyles.BeginOnly) > 0;
}
}
bool DrawEndInsertButton
{
get
{
return (insertbuttonstyle & InsertButtonStyles.EndOnly) > 0;
}
}
public class InsertItemEventArgs : HandledEventArgs
{
public readonly int Index;
public
InsertItemEventArgs(int Index)
{
this.Index = Index;
}
}
void OnInsertItem(int Index)
{
OnInsertItem(new InsertItemEventArgs(Index));
}
public event EventHandler<InsertItemEventArgs> InsertItem;
protected virtual void OnInsertItem(InsertItemEventArgs e)
{
if (InsertItem != null)
{
InsertItem(this, e);
if
(e.Handled) return;
}
source.AddNew();
MoveItem(Count - 1, e.Index);
}
void MoveItem(int Old, int New)
{
if (Old == New) return;
SuspendLayout();
source.SuspendBinding();
object
o = source[Old];
source.RemoveAt(Old);
if
(New > Old)
New--;
source.Insert(New, o);
source.ResumeBinding();
InvalidateMainPanel();
ResumeLayout();
source.Position = New;
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(false)]
[Category(ItemCategory)]
public
bool ShowInsertButtons
{
get { return insertbuttonicon != null; }
set

{
if (ShowInsertButtons == value) return;
if
(value)
{
insertbuttonicon = GetInsertButtonImage();
if
(insertbuttonstyle == InsertButtonStyles.None)
insertbuttonstyle = InsertButtonStyles.BeforeAndAfterEachItem;
}
else
insertbuttonicon = null;
InvalidateMainPanel();
}
}

private Icon insertbuttonicon;
[Category(ItemCategory)]
public
Icon InsertButtonIcon
{
get { return insertbuttonicon; }
set

{
insertbuttonicon = value;
mainpanel.Invalidate();
}
}
bool
ShouldSerializeInsertButtonIcon()
{
return insertbuttonicon != null && insertbuttonicon != DefaultInsertButtonImage;
}
public static Icon DefaultInsertButtonImage;
static Icon GetInsertButtonImage()
{
if (DefaultInsertButtonImage == null)
{
Bitmap bmp = new Bitmap(typeof(BindingNavigator), "BindingNavigator.AddNew.bmp");
bmp.MakeTransparent();
DefaultInsertButtonImage = Icon.FromHandle(bmp.GetHicon());
}
return
DefaultInsertButtonImage;
}
const int InsertButtonHeight = 16;
Rectangle
GetInsertButtonBounds(int Index)
{
Rectangle res = GetNonPaddedItemBounds(Index);
if (lefttoright)
{
res.X = Index == -1 ? 1 : res.Right + 1;
res.Width = InsertButtonHeight;
}
else

{
res.Y = Index == -1 ? 1 : res.Bottom + 1;
res.Height = InsertButtonHeight;
}
return
res;
}
#endregion
#region Selection
int selectionversion = 1;

private bool multiselect;
[DefaultValue(false)]
[Category(DataCategory)]
public
bool AllowMultiSelect
{
get { return multiselect; }
set

{
if (value == multiselect) return;
multiselect = value;
selectionversion++;
}
}
void InvalidateSelectionArea(Rectangle itembounds)
{
mainpanel.Invalidate(GetSelectionBounds(itembounds));
}
///
<summary>
///
Gets the bounds that the selection background occupies
///
</summary>
Rectangle
GetSelectionBounds(Rectangle itembounds)
{
if (lefttoright)
{
itembounds.Y = 0;
itembounds.X -= itemPadding.Left;
itembounds.Width = GetItemWidth();
itembounds.Height = Height;
itembounds.Inflate(2, 0);
}
else

{
itembounds.X = 0;
itembounds.Y -= ItemPadding.Top;
itembounds.Width = Width;
itembounds.Height = GetItemHeight();
itembounds.Inflate(0, 2);
}
return
itembounds;
}

private bool lefttoright;
[DefaultValue(false)]
[Category(BehaviorCategory)]
public
bool LeftToRight
{
get { return lefttoright; }
set

{
if (lefttoright == value) return;
lefttoright = value;
selrecimage = null;
if
(!DesignMode)
{
mainpanel.Dock = value ? DockStyle.Left : DockStyle.Top;
RefreshItems();
}
#if IncludeDesignTimeSupport
else
SetDesignTimeInstanceSize();
#endif
}
}

const int SelectButtonWidth = 14;
Bitmap selrecimage;
Bitmap
SelectedRecordImage
{
get
{
if (selrecimage == null)
{
CreateSelectRecordImage();
}
return
selrecimage;
}
}// = new Bitmap(typeof(BindingNavigator), "BindingNavigator.MoveNext.bmp");
void CreateSelectRecordImage()
{