Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / WinForms / System / WinForms / Design / Behavior / TableLayoutPanelBehavior.cs / 2 / TableLayoutPanelBehavior.cs
namespace System.Windows.Forms.Design.Behavior {
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Design;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms.Design;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
///
///
/// The TableLayoutPanelDesigner has a single instance of this behavior. Each TableLayoutPanelGlyph
// will use this one instance to resize its rows and columns.
///
internal class TableLayoutPanelBehavior : Behavior {
private TableLayoutPanelDesigner designer;//pointer back to our designer.
private Point lastMouseLoc;//used to track mouse movement deltas
private bool pushedBehavior;//tracks if we've pushed ourself onto the stack
private BehaviorService behaviorService;//used for bounds translation
private IServiceProvider serviceProvider;//cached to allow our behavior to get services
private TableLayoutPanelResizeGlyph tableGlyph;//the glyph being resized
private DesignerTransaction resizeTransaction;//used to make size adjustements within transaction
private PropertyDescriptor resizeProp;//cached property descriptor representing either the row or column styles
private PropertyDescriptor changedProp; //cached property descriptor that refers to the RowSTyles or ColumnStyles collection.
private TableLayoutPanel table;
private StyleHelper rightStyle;
private StyleHelper leftStyle;
private ArrayList styles; //List of the styles
private bool currentColumnStyles; // is Styles for Columns or Rows
#if DEBUG
private static readonly TraceSwitch tlpResizeSwitch = new TraceSwitch("TLPRESIZE", "Behavior service drag & drop messages");
#else
private static readonly TraceSwitch tlpResizeSwitch;
#endif
///
///
/// Standard constructor that caches services and clears values.
///
internal TableLayoutPanelBehavior(TableLayoutPanel panel, TableLayoutPanelDesigner designer, IServiceProvider serviceProvider) {//: base(designer) {
this.table = panel;
this.designer = designer;
this.serviceProvider = serviceProvider;
behaviorService = serviceProvider.GetService(typeof(BehaviorService)) as BehaviorService;
if (behaviorService == null) {
Debug.Fail("BehaviorService could not be found!");
return;
}
pushedBehavior = false;
lastMouseLoc = Point.Empty;
}
///
///
/// Called at the end of a resize operation -this clears state and refreshes the selection
///
private void FinishResize() {
//clear state
pushedBehavior = false;
behaviorService.PopBehavior(this);
lastMouseLoc = Point.Empty;
styles = null;
// fire ComponentChange events so this event is undoable
IComponentChangeService cs = serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
if (cs != null && changedProp != null) {
cs.OnComponentChanged(table, changedProp, null, null);
changedProp = null;
}
//attempt to refresh the selection
SelectionManager selManager = serviceProvider.GetService(typeof(SelectionManager)) as SelectionManager;
if (selManager != null) {
selManager.Refresh();
}
}
///
///
/// This method is called when we lose capture during our resize actions.
/// Here, we clear our state and cancel our transaction.
///
public override void OnLoseCapture(Glyph g, EventArgs e) {
if (pushedBehavior) {
FinishResize();
// If we still have a transaction, roll it back.
//
if (resizeTransaction != null) {
DesignerTransaction t = resizeTransaction;
resizeTransaction = null;
using (t) {
t.Cancel();
}
}
}
}
internal struct StyleHelper
{
public int index;
public PropertyDescriptor styleProp;
public TableLayoutStyle style;
}
///
///
/// This method will cache off our glyph, set the proper selection and
// push this behavior onto the stack.
///
public override bool OnMouseDown(Glyph g, MouseButtons button, Point mouseLoc) {
//we only care about the right mouse button for resizing
if (button == MouseButtons.Left && g is TableLayoutPanelResizeGlyph) {
tableGlyph = g as TableLayoutPanelResizeGlyph;
//select the table
ISelectionService selSvc = serviceProvider.GetService(typeof(ISelectionService)) as ISelectionService;
if (selSvc != null) {
selSvc.SetSelectedComponents(new object[] {designer.Component}, SelectionTypes.Primary);
}
bool isColumn = tableGlyph.Type == TableLayoutPanelResizeGlyph.TableLayoutResizeType.Column;
//cache some state
lastMouseLoc = mouseLoc;
resizeProp = TypeDescriptor.GetProperties(tableGlyph.Style)[isColumn ? "Width" : "Height"];
Debug.Assert(resizeProp != null, "Unable to get the resize property for tableGlyph's Style");
IComponentChangeService cs = serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
if (cs != null) {
changedProp = TypeDescriptor.GetProperties(table)[isColumn ? "ColumnStyles" : "RowStyles"];
int[] widths = isColumn ? table.GetColumnWidths() : table.GetRowHeights();
if (changedProp != null) {
GetActiveStyleCollection(isColumn);
if (styles != null && CanResizeStyle(widths)) {
IDesignerHost host = serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (host != null) {
resizeTransaction = host.CreateTransaction(SR.GetString(SR.TableLayoutPanelRowColResize, (isColumn ? "Column" : "Row"), designer.Control.Site.Name));
}
try {
int moveIndex = styles.IndexOf(tableGlyph.Style);
rightStyle.index = IndexOfNextStealableStyle(true /*forward*/, moveIndex, widths);
rightStyle.style = (TableLayoutStyle)styles[rightStyle.index];
rightStyle.styleProp = TypeDescriptor.GetProperties(rightStyle.style)[isColumn ? "Width" : "Height"];
leftStyle.index = IndexOfNextStealableStyle(false /*backwards*/, moveIndex, widths);
leftStyle.style = (TableLayoutStyle)styles[leftStyle.index];
leftStyle.styleProp = TypeDescriptor.GetProperties(leftStyle.style)[isColumn ? "Width" : "Height"];
Debug.Assert(leftStyle.styleProp != null && rightStyle.styleProp != null, "Couldn't find property descriptor for width or height");
cs.OnComponentChanging(table, changedProp);
}
catch (CheckoutException checkoutException) {
if (CheckoutException.Canceled.Equals(checkoutException)) {
if ((resizeTransaction != null) && (!resizeTransaction.Canceled)) {
resizeTransaction.Cancel();
}
}
throw;
}
}
else {
return false;
}
}
}
//push this resizebehavior
behaviorService.PushCaptureBehavior(this);
pushedBehavior = true;
}
return false;
}
private void GetActiveStyleCollection(bool isColumn) {
if ((styles == null || isColumn != currentColumnStyles) && table != null) {
styles = new ArrayList(changedProp.GetValue(table) as TableLayoutStyleCollection);
currentColumnStyles = isColumn;
}
}
private bool ColumnResize {
get {
bool ret = false;
if (tableGlyph != null) {
ret = tableGlyph.Type == TableLayoutPanelResizeGlyph.TableLayoutResizeType.Column;
}
return ret;
}
}
private bool CanResizeStyle(int[] widths) {
bool canStealFromRight = false;
bool canStealFromLeft = false;
int moveIndex = ((IList)styles).IndexOf(tableGlyph.Style);
if (moveIndex > -1 && moveIndex != styles.Count) {
canStealFromRight = IndexOfNextStealableStyle(true, moveIndex, widths) != -1;
canStealFromLeft = IndexOfNextStealableStyle(false, moveIndex, widths) != -1;
}
else {
Debug.Fail("Can't find style " + moveIndex);
return false;
}
return canStealFromRight && canStealFromLeft;
}
private int IndexOfNextStealableStyle(bool forward, int startIndex, int[] widths) {
int stealIndex = -1;
if (styles != null) {
if (forward) {
for (int i = startIndex + 1; i < styles.Count; i++) {
if (((TableLayoutStyle)styles[i]).SizeType != SizeType.AutoSize && widths[i] >= DesignerUtils.MINUMUMSTYLESIZEDRAG) {
stealIndex = i;
break;
}
}
}
else {
for (int i = startIndex; i >= 0; i--) {
if (((TableLayoutStyle)styles[i]).SizeType != SizeType.AutoSize && widths[i] >= DesignerUtils.MINUMUMSTYLESIZEDRAG) {
stealIndex = i;
break;
}
}
}
}
return stealIndex;
}
///
///
/// If we have pushed ourselves onto the stack then use our propertyDescriptor to
/// make realtime adjustments to the table's rows or columns.
///
[SuppressMessage("Microsoft.Portability", "CA1902:AvoidTestingForFloatingPointEquality")]
[SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
public override bool OnMouseMove(Glyph g, MouseButtons button, Point mouseLoc) {
if (pushedBehavior) {
bool isColumn = ColumnResize;
GetActiveStyleCollection(isColumn);
if (styles != null) {
int rightIndex = rightStyle.index;
int leftIndex = leftStyle.index;
int delta = isColumn ? mouseLoc.X - lastMouseLoc.X : mouseLoc.Y - lastMouseLoc.Y;
if (isColumn && table.RightToLeft == RightToLeft.Yes) {
delta *= -1;
}
if (delta == 0) {
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "0 mouse delta");
return false;
}
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "BEGIN RESIZE");
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "mouse delta: " + delta);
int[] oldWidths = isColumn ? table.GetColumnWidths() : table.GetRowHeights();
int[] newWidths = oldWidths.Clone() as int[];
newWidths[rightIndex] -= delta;
newWidths[leftIndex ] += delta;
if (newWidths[rightIndex] < DesignerUtils.MINUMUMSTYLESIZEDRAG ||
newWidths[leftIndex] < DesignerUtils.MINUMUMSTYLESIZEDRAG) {
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "Bottomed out.");
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "END RESIZE\n");
return false;
}
// now we must renormalize our new widths into the correct sizes
table.SuspendLayout();
int totalSize = oldWidths[rightIndex] + oldWidths[leftIndex];
int totalPercent = 0;
//simplest case: two absolute columns just affect each other.
if (((TableLayoutStyle)styles[rightIndex]).SizeType == SizeType.Absolute &&
((TableLayoutStyle)styles[leftIndex]).SizeType == SizeType.Absolute) {
// VSWhidbey 465751
// The dimensions reported by GetColumnsWidths() are different
// than the style dimensions when the TLP has borders. Instead
// of always setting the new size directly based on the reported
// sizes, we now base them on the style size if necessary.
float newRightSize = newWidths[rightIndex];
float rightStyleSize = (float) rightStyle.styleProp.GetValue(rightStyle.style);
if (rightStyleSize != oldWidths[rightIndex]) {
newRightSize = Math.Max(rightStyleSize - delta, DesignerUtils.MINUMUMSTYLESIZEDRAG);
}
float newLeftSize = newWidths[leftIndex];
float leftStyleSize = (float) leftStyle.styleProp.GetValue(leftStyle.style);
if (leftStyleSize != oldWidths[leftIndex]) {
newLeftSize = Math.Max(leftStyleSize + delta, DesignerUtils.MINUMUMSTYLESIZEDRAG);
}
rightStyle.styleProp.SetValue(rightStyle.style, newRightSize);
leftStyle.styleProp.SetValue(leftStyle.style, newLeftSize);
}
// two percents just steal from each other.
else if(((TableLayoutStyle)styles[rightIndex]).SizeType == SizeType.Percent &&
((TableLayoutStyle)styles[leftIndex ]).SizeType == SizeType.Percent) {
for (int i = 0; i < styles.Count; i++) {
if (((TableLayoutStyle)styles[i]).SizeType == SizeType.Percent) {
totalPercent += oldWidths[i];
}
}
for (int j = 0; j < 2; j++) {
int i = j == 0 ? rightIndex : leftIndex;
float newSize = (float) newWidths[i] * 100 / (float) totalPercent;
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "NewSize " + newSize);
PropertyDescriptor prop = TypeDescriptor.GetProperties(styles[i])[isColumn ? "Width" : "Height"];
if (prop != null) {
prop.SetValue(styles[i], newSize);
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "Resizing column (per) " + i.ToString(CultureInfo.InvariantCulture) + " to " + newSize.ToString(CultureInfo.InvariantCulture));
}
}
}
else {
#if DEBUG
for (int i = 0; i < oldWidths.Length; i++) {
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "Col " + i + ": Old: " + oldWidths[i] + " New: " + newWidths[i]);
}
#endif
//mixed - just update absolute
int absIndex = ((TableLayoutStyle)styles[rightIndex]).SizeType == SizeType.Absolute ? rightIndex : leftIndex;
PropertyDescriptor prop = TypeDescriptor.GetProperties(styles[absIndex])[isColumn ? "Width" : "Height"];
if (prop != null) {
// VSWhidbey 465751
// The dimensions reported by GetColumnsWidths() are different
// than the style dimensions when the TLP has borders. Instead
// of always setting the new size directly based on the reported
// sizes, we now base them on the style size if necessary.
float newAbsSize = newWidths[absIndex];
float curAbsStyleSize = (float) prop.GetValue(styles[absIndex]);
if (curAbsStyleSize != oldWidths[absIndex]) {
newAbsSize = Math.Max(absIndex == rightIndex ? curAbsStyleSize - delta : curAbsStyleSize + delta,
DesignerUtils.MINUMUMSTYLESIZEDRAG);
}
prop.SetValue(styles[absIndex], newAbsSize);
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose, "Resizing column (abs) " + absIndex.ToString(CultureInfo.InvariantCulture) + " to " + newWidths[absIndex]);
}
else {
Debug.Fail("Can't resize - no propertyescriptor for column");
}
}
table.ResumeLayout(true);
// now determine if the values we pushed into the TLP
// actually had any effect. If they didn't,
// we delay updating the last mouse position so that
// next time a mouse move message comes in the delta is larger.
bool updatedSize = true;
int[] updatedWidths = isColumn ? table.GetColumnWidths() : table.GetRowHeights();
for(int i = 0; i < updatedWidths.Length; i++) {
if (updatedWidths[i] == oldWidths[i] && newWidths[i] != oldWidths[i]) {
updatedSize = false;
}
}
if (updatedSize) {
lastMouseLoc = mouseLoc;
}
}
else {
lastMouseLoc = mouseLoc;
}
}
Debug.WriteLineIf(tlpResizeSwitch.TraceVerbose && pushedBehavior, "END RESIZE\n");
return false;
}
///
///
/// Here, we clear our cached state and commit the transaction.
///
public override bool OnMouseUp(Glyph g, MouseButtons button) {
if (pushedBehavior) {
FinishResize();
//commit transaction
if (resizeTransaction != null) {
DesignerTransaction t = resizeTransaction;
resizeTransaction = null;
using (t) {
t.Commit();
}
resizeProp = null;
}
}
return false;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EventRecord.cs
- OutputCache.cs
- TransactionScope.cs
- AuthStoreRoleProvider.cs
- Hyperlink.cs
- basecomparevalidator.cs
- MissingSatelliteAssemblyException.cs
- ApplyTemplatesAction.cs
- CopyNodeSetAction.cs
- DataSourceCache.cs
- XmlSchemaSimpleContentRestriction.cs
- MenuBindingsEditorForm.cs
- IntPtr.cs
- OracleConnectionString.cs
- XmlElementAttributes.cs
- OneWayElement.cs
- RoleManagerModule.cs
- SimpleRecyclingCache.cs
- ProgressBar.cs
- BooleanToSelectiveScrollingOrientationConverter.cs
- ConstrainedDataObject.cs
- RangeBaseAutomationPeer.cs
- SimpleWorkerRequest.cs
- ToolStripCodeDomSerializer.cs
- XmlReflectionImporter.cs
- WorkflowMessageEventArgs.cs
- MetaModel.cs
- BindingListCollectionView.cs
- TargetControlTypeAttribute.cs
- LookupBindingPropertiesAttribute.cs
- GifBitmapDecoder.cs
- _CookieModule.cs
- ConfigXmlCDataSection.cs
- UpdateTranslator.cs
- AuthenticationService.cs
- BaseTemplateParser.cs
- AvTraceFormat.cs
- XmlSignatureManifest.cs
- DynamicObject.cs
- QuotedPrintableStream.cs
- QuaternionIndependentAnimationStorage.cs
- GAC.cs
- FontStyle.cs
- ScriptIgnoreAttribute.cs
- FlowchartDesigner.Helpers.cs
- SEHException.cs
- SqlCommand.cs
- RetrieveVirtualItemEventArgs.cs
- RecognizedWordUnit.cs
- _ServiceNameStore.cs
- SqlClientWrapperSmiStream.cs
- CookieProtection.cs
- ControlSerializer.cs
- Message.cs
- SqlBulkCopyColumnMappingCollection.cs
- PieceNameHelper.cs
- OrderByQueryOptionExpression.cs
- CodeMemberField.cs
- MetadataItemEmitter.cs
- CapabilitiesState.cs
- XomlCompilerError.cs
- RegisteredExpandoAttribute.cs
- ShaperBuffers.cs
- SQLDoubleStorage.cs
- WriteableBitmap.cs
- NamedPipeChannelListener.cs
- HttpFileCollection.cs
- PageContentCollection.cs
- SmiRequestExecutor.cs
- XmlIlVisitor.cs
- ProxyFragment.cs
- BindingExpression.cs
- lengthconverter.cs
- AnalyzedTree.cs
- PageHandlerFactory.cs
- UInt16Storage.cs
- PeerCredentialElement.cs
- VisualProxy.cs
- CodeActivityContext.cs
- RtfToXamlReader.cs
- NamespaceMapping.cs
- MessageBox.cs
- SelectionChangedEventArgs.cs
- SocketException.cs
- ViewStateModeByIdAttribute.cs
- XmlNodeWriter.cs
- ColumnClickEvent.cs
- ItemMap.cs
- selecteditemcollection.cs
- CurrencyManager.cs
- TransformedBitmap.cs
- SafeHandle.cs
- ElementNotEnabledException.cs
- _Connection.cs
- EdmPropertyAttribute.cs
- DefaultProfileManager.cs
- FontFamilyValueSerializer.cs
- ISO2022Encoding.cs
- Geometry.cs
- MSAAWinEventWrap.cs