HotDog's Blog

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

vbCity Blogs moved to:
http://cs.vbcity.com/blogs
  Home :: Syndication  :: Login

OctNovember 2009Dec
SMTWTFS
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

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()
{
selrecimage = GetTriangleBitmap(lefttoright, 10, 10, Brushes.LightGray);
}
private bool showselectbuttons = false;
[DefaultValue(false)]
[Category(ItemCategory)]
public
bool ShowSelectButtons
{
get { return showselectbuttons; }
set

{
if (showselectbuttons == value) return;
showselectbuttons = value;
ResetItemSize();
}
}

void InvalidateSelected(int version)
{
for (int i = 0; i < items.Count; i++)
{
if (items[i].SelectedVersion == version)
InvalidateSelectionArea(GetItemBounds(i));
}
}
void SwitchSelect(int index)
{
int curindex = SelectedIndex;
Item item = GetItem(index);
bool
selected = item.SelectedVersion == selectionversion;
if
(selected)
{
//deselect
item.SelectedVersion--;
if
(index == curindex)
{
}
}
else

{
//select
item.SelectedVersion = selectionversion;
//make sure current item has the proper version
if
(curindex != -1)
GetItem(curindex).SelectedVersion = selectionversion;
}


InvalidateSelectionArea(GetItemBounds(index));
}
System.Collections.IEnumerable GetSelectedItems(int selectionversion)
{
int sel = SelectedIndex;
for
(int i = 0; i < items.Count; i++)
{
if (i != sel && items[i].SelectedVersion == selectionversion)
yield return source[i];
}
}
public
System.Collections.IEnumerable GetSelectedItems()
{
if (source == null)
yield break;
yield return source.Current;
if
(multiselect)
{
foreach (object o in GetSelectedItems(selectionversion))
{
yield return o;
}
}
}
void DeleteItems(System.Collections.IEnumerable Items)
{
List<object> list = new List<object>((IEnumerable<object>)Items);
foreach
(object o in list)
{
source.Remove(o);
}
}
public
void DeleteSelectedItems()
{
if (!multiselect)
{
source.RemoveCurrent();
}
else

{
DeleteItems(GetSelectedItems());
}
}
#endregion
#region DragDrop
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Category(BehaviorCategory)]
public
override bool AllowDrop
{
get
{
return mainpanel.AllowDrop;
}
set

{
mainpanel.AllowDrop = value;
}
}
private bool autodrag;
[Category(BehaviorCategory)]
[DefaultValue(false)]
public
bool AutoDrag
{
get { return autodrag; }
set
{ autodrag = value; }
}

void SetAllowDrop()
{
AllowDrop = allowreorder;
}
private bool allowreorder;
[DefaultValue(false)]
[Category(BehaviorCategory)]
public
bool AllowReordering
{
get { return allowreorder; }
set

{
allowreorder = value;
SetAllowDrop();
}
}
public class DragStartEventArgs : HandledEventArgs
{
public readonly int Index;
public
object DragObject;
public
DragStartEventArgs(int Index)
{
this.Index = Index;
}
public string DragObjectTypeName
{
get
{
if (DragObject == null) return null;
return
DragObject.GetType().FullName;
}
}
}
public event EventHandler<DragStartEventArgs> DragStart;
//DragStartEventArgs currentdrag;
void
OnDragStart(int Index)
{
if (Index < 0) return;
DragStartEventArgs
e = new DragStartEventArgs(Index);
e.DragObject = source.Current;
OnDragStart(e);
}
protected virtual void OnDragStart(DragStartEventArgs e)
{
if (DragStart != null)
{
DragStart(this, e);
if
(e.Handled) return;
}
if
(e.DragObject != null)
{
DoDragDrop(e.DragObject, DragDropEffects.All);
}
}
public Type GetItemType()
{
if (source == null) return null;
return
ListBindingHelper.GetListItemType(source.DataSource, source.DataMember);
}
int GetIndex(DragEventArgs e)
{
Point p = GetClientPoint(e);
int
i = GetIndex(p);
if
(i < 0 || i == source.Position) return -1;
float
margin;
if
(lefttoright)
{
margin = ((float)p.X - GetItemLeft(i)) / GetItemWidth();
}
else

{
margin = ((float)p.Y - GetItemTop(i)) / GetItemHeight();
}
if
(margin > .5)
i++;
if (i > Count)
i = Count;
return i;
}
Point GetClientPoint(DragEventArgs e)
{
Point p = new Point(e.X, e.Y);
return
mainpanel.PointToClient(p);
}

int? DragInsertIndex;
protected override void OnDragOver(DragEventArgs e)
{
if (e.Data.GetDataPresent(GetItemType()))
{
object o = e.Data.GetData(GetItemType());
if
(allowreorder && o == source.Current)
{
int i = GetIndex(e);
if (DragInsertIndex != i)
ClearDragInsertIndex();
if (i != -1)
{
e.Effect = DragDropEffects.Move;
DragInsertIndex = i;
mainpanel.InvalidateDragInsert(i);
return
;
}
}
}
e.Effect = DragDropEffects.None;
base
.OnDragOver(e);
}
void ClearDragInsertIndex()
{
if (DragInsertIndex != null)
{
int i = DragInsertIndex.Value;
DragInsertIndex = null;
mainpanel.InvalidateDragInsert(i);
}
}
protected override void OnDragLeave(EventArgs e)
{
ClearDragInsertIndex();
base
.OnDragLeave(e);
}
protected override void OnDragDrop(DragEventArgs e)
{
if (DragInsertIndex != null)
{
MoveItem(source.Position, DragInsertIndex.Value);
ClearDragInsertIndex();
}
base
.OnDragDrop(e);
}
#endregion
#region Header
Header header;
[DefaultValue(false)]
[Category(HeaderCategory)]
public
bool ShowHeader
{
get { return header != null; }
set

{
if (ShowHeader == value) return;
if
(value)
{
InitHeader();
}
else

{
header.Dispose();
header = null;
}
}
}
void InitHeader()
{
header = new Header();
header.Height = headerheight;
Controls.Add(header);
#if IncludeDesignTimeSupport
InitHeaderDesigner();
#endif
if (navigator != null)
navigator.SendToBack();
}

const int DefaultHeaderHeight = 30;
private
int headerheight = DefaultHeaderHeight;
[Category(HeaderCategory)]
[DefaultValue(DefaultHeaderHeight)]
public
int HeaderHeight
{
get { return headerheight; }
set

{
headerheight = value;
if
(header != null)
header.Height = value;
}
}

/// <summary>
///
Direct access to the controls of header portion of the control
///
</summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
ControlCollection HeaderControlCollection
{
get
{
if (header == null) return null;
return
header.Controls;
}
}
/// <summary>
///
Meant for the designer serialization for header controls
///
</summary>
[DefaultValue(null)]
[Browsable(false)]
public
Control[] HeaderControls
{
get
{
if (header == null) return null;
Control
[] ctr = new Control[header.Controls.Count];
for
(int i = 0; i < ctr.Length; i++)
{
ctr[i] = header.Controls[i];
}
return
ctr;
}
set

{
ShowHeader = value != null && value.Length > 0;
if
(ShowHeader)
header.Controls.AddRange(value);
}
}

#if
IncludeDesignTimeSupport
[Designer(typeof(DropOnlyDesigner))]
[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 Header : Panel
{
public Header()
{
Dock = DockStyle.Top;
}
Pen p = Pens.Black;
protected
override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int
y = Bottom - 1;
e.Graphics.DrawLine(p, 0, y, Width, y);
}
}

#endregion
#region ISupportInitialize Members
int initializing;
///
<summary>
///
Indicates if the control is inside the initialization state.
///
(in other words, between the BeginInit and EndInit inside the designer generated code)
///
</summary>
protected
bool IsInitializing
{
get
{
return initializing > 0;
}
}
void ISupportInitialize.BeginInit()
{
initializing++;
}
void ISupportInitialize.EndInit()
{
if (--initializing == 0)
{
if (itemsize != null)
ResetItemSize();
ResetList();
}
}
#endregion
}
public enum ItemSizeMode
{
/// <summary>
///
Default mode: each item has the same size based on the layout of the controls added to it
///
</summary>
Automatic,
///
<summary>
///
The size for each item is variable. The size per item is determined by the layout of the controls
///
</summary>
Variable,
///
<summary>
///
The size for each item is variable. The user can change the size of an item in runtime.
///
</summary>
VariableUserSizable,
///
<summary>
///
Each item is fixed on whatever size is assigned to the ItemSize property
///
</summary>
Fixed
}
}



#region
Design time support (needs a reference to System.Design)

//this part contains the functionality for design time support
//if wanted this part could be omitted in final distrubution code
//(wouldn't bother to myself, but perhaps it is needed in the future
// for compact framework distrubution or the likes)

#if
IncludeDesignTimeSupport

namespace
Subro.Controls
{
using System.ComponentModel.Design;
using
System.Windows.Forms.Design;
using
System.Windows.Forms.Design.Behavior;
partial class ContinuousControl
{
#region designer

void SetDesignTimeInstanceSize()
{
/*
instance.Left = GetItemLeft(0);
instance.Width = scrollpanel.Width - instance.Left;
instance.Height = scrollpanel.Height;*/

instance.Location = GetDesignerOffset();
instance.Width = scrollpanel.Width - instance.Left;
instance.Height = scrollpanel.Height - instance.Top;
instance.Invalidate();
}
void InitDesignEnvironment()
{
mainpanel.Dock = DockStyle.Fill;
instance.Dock = DockStyle.None;
instance.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
SetDesignTimeInstanceSize();
}
void InitHeaderDesigner()
{
if (Site == null) return;
INestedContainer
cont = (INestedContainer)GetService(typeof(INestedContainer));
if
(cont != null)
cont.Add(header, "Header");
}
class ContinuousControlDesigner : ControlDesigner
{
public override void Initialize(IComponent component)
{
ContinuousControl cc = (component as ContinuousControl);
if
(component.GetType() == typeof(ContinuousControl))
cc.Init(); //for inheriting controls, Init allready is done in the constructor
base.Initialize(component);
if (!EnableDesignMode(cc.instance, "Controls"))
MessageBox.Show("Could not create child designer");
//designercontrols = new List<Control>(cc.GetDesignerControls());
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
foreach
(Control dc in cc.GetDesignerControls())
{
IDesigner id = host.GetDesigner(dc);
if
(id == null)
{
EnableDesignMode(dc, dc.Name);
}
}
}
}
class
ContinuousControlDocumentDesigner : DocumentDesigner
{
public override void Initialize(IComponent component)
{
ContinuousControl cc = component as ContinuousControl;
cc._Instance = cc.instance;
base
.Initialize(component);
cc._Instance = null;
}
}
/// <summary>
///
inheriting classes can override this function to add any
///
controls that should be exposed to the designer this control
///
is dropped on
///
</summary>
///
<returns></returns>
protected
virtual IEnumerable<Control> GetDesignerControls()
{
yield break;
}
class DropOnlyDesigner : ParentControlDesigner
{
protected virtual ContinuousControl Owner
{
get
{
return Control.Parent as ContinuousControl;
}
}

protected override void PreFilterProperties(System.Collections.IDictionary properties)
{
PropertyDescriptor pdo = (PropertyDescriptor)properties["Owner"];
if
(pdo == null)
pdo = (PropertyDescriptor)properties["Parent"];
properties.Clear();
properties.Add("Owner", pdo);
}

public override GlyphCollection GetGlyphs(GlyphSelectionType selectionType)
{
GlyphCollection coll = base.GetGlyphs(selectionType);
if
(selectionType == GlyphSelectionType.SelectedPrimary)
{
coll.Add(CreateGlyph(Owner));
}
return
coll;
}

#region select owner glyph
SelectParentGlyph CreateGlyph()
{
return CreateGlyph(Control.Parent);
}
SelectParentGlyph
CreateGlyph(Control ParentControl)
{
Rectangle r = BehaviorService.ControlRectInAdornerWindow(ParentControl);
r.X = r.Right;
r.Width = 30;
return
new SelectParentGlyph(r, ParentControl);
}
class SelectParentGlyph : Glyph
{
SelectParentBehavior beh;
public
readonly Control Owner;
Rectangle
bounds;
public
SelectParentGlyph(Rectangle rect, Control Owner)
: base(new SelectParentBehavior())
{
beh = Behavior as SelectParentBehavior;
this
.Owner = Owner;
this
.bounds = rect;
}
public override Cursor GetHitTest(Point p)
{
if (bounds.Contains(p))
return Cursors.Hand;
return null;
}
public override void Paint(PaintEventArgs pe)
{
if (textsize == null)
{
SizeF size = pe.Graphics.MeasureString(Text, font, bounds.Width, sf);
textsize = Size.Ceiling(size);
bounds.Size = textsize.Value;
}
pe.Graphics.DrawRectangle(Pens.Black, bounds);
pe.Graphics.DrawString(Text, font, Brushes.Black, Bounds, sf);
}
Size? textsize;
string
Text = "Select Owner";
StringFormat
sf = new StringFormat(StringFormatFlags.DirectionVertical);
Font
font = new Font(FontFamily.GenericSansSerif, 7);

public override Rectangle Bounds
{
get
{
return bounds;
}
}

protected void SelectParent()
{
try
{
IServiceProvider provider = Owner.Site;
if
(provider == null) throw new Exception(Owner.Name + " does not contain a service provider");
ISelectionService
sel = (ISelectionService)provider.GetService(typeof(ISelectionService));
sel.SetSelectedComponents(new Control[] { Owner }, SelectionTypes.Primary);
}
catch
(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
protected class SelectParentBehavior : Behavior
{
public override bool OnMouseDown(Glyph g, MouseButtons button, Point mouseLoc)
{
SelectParentGlyph sog = g as SelectParentGlyph;
if
(sog == null)
return base.OnMouseDown(g, button, mouseLoc);
sog.SelectParent();
return
false;
}
}
}
#endregion
}
class InstanceDesigner : DropOnlyDesigner
{
new ControlInstance Control
{
get
{
return base.Control as ControlInstance;
}
}
protected override ContinuousControl Owner
{
get { return Control.owner; }
}
DesignerVerb selectowner;
ISelectionService
selservice;
public
override void Initialize(IComponent component)
{
base.Initialize(component);
Owner.InitDesignEnvironment();
if (selectowner == null)
{
selectowner = new DesignerVerb("Select owner", new EventHandler(SelectOwner));
Verbs.Add(selectowner);
selservice = (ISelectionService)GetService(typeof(ISelectionService));
}
}

void DeleteOwner(object sender, EventArgs e)
{
Host.DestroyComponent(Owner);
}
void
SelectOwner(object sender, EventArgs e)
{
SelectOwner();
}
void
SelectOwner()
{
selservice.SetSelectedComponents(new IComponent[] { Owner }, SelectionTypes.Primary);
}
protected override Control GetParentForComponent(IComponent component)
{
return Owner;
}
IDesignerHost host;
IDesignerHost
Host
{
get
{
if (host == null)
host = (IDesignerHost)GetService(typeof(IDesignerHost));
return host;
}
}
protected override void PreFilterAttributes(System.Collections.IDictionary attributes)
{
foreach (object var in attributes)
{
}
base
.PreFilterAttributes(attributes);
}

protected override void OnPaintAdornments(PaintEventArgs pe)
{
base.OnPaintAdornments(pe);
if (Control == null) return;

pe.Graphics.FillRectangle(
new SolidBrush(Owner.scrollpanel.BackColor),
Control.ClientRectangle);
Point p = Owner.GetDesignerOffset();
pe.Graphics.TranslateTransform(-p.X, -p.Y);
Rectangle bounds = Owner.GetNonPaddedItemBounds(0);
pe.Graphics.FillRectangle(
new SolidBrush(Control.BackColor),
bounds);
Owner.mainpanel.Paint(pe.Graphics);
}
}
Point GetDesignerOffset()
{
Rectangle r = GetNonPaddedItemBounds(0);
return
r.Location;
}
#endregion
}
}

#endif

#endregion
. . .
posted on Thursday, October 26, 2006 8:04 AM