Public Function LastUsedColumnInRow(rRow As Range) As Long
LastUsedColumnInRow = Range("XFD" & rRow.row).End(xlToLeft).Column
End Function[ExcelFunction(IsMacroType = true)]public static object LastUsedColumnInRow([ExcelArgument(AllowReference = true)] object objRange){ if (objRange.GetType().ToString() == "ExcelDna.Integration.ExcelReference") { ExcelReference xlr = (ExcelReference)objRange; int row = xlr.RowFirst; int newCol = ExcelDnaUtil.ExcelLimits.MaxColumns - 1; ExcelReference xlref = new ExcelReference(row, row, newCol, newCol, xlr.SheetId); while (xlref.GetValue() == ExcelEmpty.Value && newCol > -1) { newCol--; xlref = new ExcelReference(row, row, newCol, newCol); } return xlref.ColumnLast + 1; } else { return false; }}[ExcelFunction(IsMacroType = true)]public static object LastUsedColumnInRow2([ExcelArgument(AllowReference = true)] object objRange){ if (objRange.GetType().ToString() == "ExcelDna.Integration.ExcelReference") { ExcelReference xlr = (ExcelReference)objRange; int row = xlr.RowFirst; int firstCol = xlr.ColumnFirst; ExcelReference xlref = new ExcelReference(row, row, firstCol, firstCol, xlr.SheetId); ExcelReference xlEnd = xlref.End(DirectionType.ToRight); return xlEnd.ColumnLast + 1; } else { return false; }}
// Directionpublic enum DirectionType{ ToLeft = 1, ToRight = 2, Up = 3, Down = 4}// Get last used cell in the specified directionpublic static ExcelReference End(this ExcelReference reference, DirectionType direction){ ExcelReference end = null; using (new ExcelSelectionHelper(reference)) { // myReference is selected now... ??? XlCall.Excel(XlCall.xlcSelectEnd, (int)direction); ExcelReference selection = (ExcelReference)XlCall.Excel(XlCall.xlfSelection); int row = selection.RowFirst; int col = selection.ColumnFirst; end = new ExcelReference(row, row, col, col, selection.SheetId); } return end;}public enum DirectionType
{
Up = 3,
ToRight = 2,
Down = 4,
ToLeft = 1
}
public static ExcelReference End( this ExcelReference reference, DirectionType direction )
{
ExcelReference end = null;
reference.RestoreSelection( () =>
{
if (
( direction == DirectionType.Down && reference.Offset( 1, 0 ).GetValue() == ExcelEmpty.Value ) ||
( direction == DirectionType.ToRight && reference.Offset( 0, 1 ).GetValue() == ExcelEmpty.Value ) ||
( direction == DirectionType.ToLeft && reference.Offset( 0, -1 ).GetValue() == ExcelEmpty.Value ) ||
( direction == DirectionType.Up && reference.Offset( -1, 0 ).GetValue() == ExcelEmpty.Value )
)
{
end = reference;
}
else
{
// Govert talks about 'messiness' at http://stackoverflow.com/a/10920622/166231, but pretty straight forward
XlCall.Excel( XlCall.xlcSelectEnd, (int)direction );
var selection = XlCall.Excel( XlCall.xlfSelection ) as ExcelReference;
var row = selection.RowFirst;
var col = selection.ColumnFirst;
end = new ExcelReference( row, row, col, col, selection.SheetId );
}
} );
return end;
}
Then in a static class:
public static void RestoreSelection( this ExcelReference reference, Action action )
{
ApplicationEx.RestoreSelection( action, reference );
}
public static void RestoreSelection( Action action, ExcelReference range = null )
{
// https://groups.google.com/d/msg/exceldna/h3SqSA8DkPc/X0uxH4pUBgAJ - read comment about his SelectionHelper
bool updating = ScreenUpdating;
try
{
if ( updating ) ScreenUpdating = false;
//remember the current active cell
var current = new
{
Selection = XlCall.Excel( XlCall.xlfSelection ),
Cell = XlCall.Excel( XlCall.xlfActiveCell )
};
if ( range != null )
{
//select caller worksheet containing range caller desires to be active
// (need to do this before reading selection/cell on this sheet)
var rangeSheet = (string)XlCall.Excel( XlCall.xlSheetNm, range );
XlCall.Excel( XlCall.xlcWorkbookSelect, new object[] { rangeSheet } );
}
// record selection and active cell on the sheet we want to select
var sheetCurrent = range != null
? new
{
Selection = XlCall.Excel( XlCall.xlfSelection ),
Cell = XlCall.Excel( XlCall.xlfActiveCell ),
OriginalSheet = (string)XlCall.Excel( XlCall.xlSheetNm, current.Selection )
}
: null;
if ( range != null )
{
// Select the range caller desires to be active...
XlCall.Excel( XlCall.xlcSelect, range );
}
action();
// Now restore everything...
if ( range != null )
{
// Reset the selection on the target sheet
XlCall.Excel( XlCall.xlcSelect, sheetCurrent.Selection, sheetCurrent.Cell );
// Reset the sheet originally selected
XlCall.Excel( XlCall.xlcWorkbookSelect, new object[] { sheetCurrent.OriginalSheet } );
}
// Reset the selection in the active sheet (some bugs make this change sometimes too)
XlCall.Excel( XlCall.xlcSelect, current.Selection, current.Cell );
}
finally
{
if ( updating ) ScreenUpdating = true;