Spread Windows Forms 15.0
Spread Windows Forms 15.0 Product Documentation / Developer's Guide / Customizing Drawing / Creating Enhanced Camera Shape
In This Topic
    Creating Enhanced Camera Shape
    In This Topic

    Camera shape, as the name suggests, is a mirror image of a referenced area in a spreadsheet. It is a dynamic image, meaning that any change in the referenced region is reflected in the image as well. You can create a camera shape by referring to Creating Camera Shapes topic.

    Additionally, Spread for Winforms provides an enhanced camera shape that inherits all the features of the enhanced shape engine. For example, the enhanced camera shape can be moved, resized, rotated, and supported for Excel I/O. They can also be grouped or ungrouped with other shapes and copy-pasted from one sheet to another.

    The enhanced camera shape displays the contents of a cell range by linking the cell range to a shape. On selecting the camera shape, it displays the source cell range in the formula bar. You can edit this cell range or defined name (of any cell range) to dynamically switch the camera shape's source data.

    Adding Camera Shape

    You can add the enhanced camera shape using the IPicture.Paste method. It accepts parameters such as the destination in the sheet and whether to establish a link to the source of the pasted picture. The RichClipboard property needs to be true to use this method.

    You can also convert a picture to a camera shape by using IShape.Formula property to set the shape formula.

    The implementation of the new camera shape takes effect if EnhancedShapeEngine is true.

    C#
    Copy Code
    fpSpread1.Features.EnhancedShapeEngine = true;
    fpSpread1.Features.RichClipboard = true;
    
    // Adding camera shape by using IPictures.Paste method
    
    TestActiveSheet.Cells["A1:E7"].Copy(true);      // Have to Copy with bool showUI = true
    TestActiveSheet.Pictures.Paste("D11", true);    // CameraShape refers to Sheet1!$A$1:$E$7 is created
    TestActiveSheet.Pictures.Paste("F11", false);   // A picture that snap content of A1:E7 is created
    
    // Changing a picture to camera shape
                
    IShape picture = TestActiveSheet.Shapes.AddPictureToCell(null, true, true, 1, 3);
    picture.Formula = "A1:E7";
    TestWorkBook.Names.Add("_name", "$A$1:$B$1");
    IShape picture1 = TestActiveSheet.Shapes.AddPictureToCell(null, true, true, 6, 0);
    picture1.Formula = "_name";
    
    Visual Basic
    Copy Code
    FpSpread1.Features.EnhancedShapeEngine = True
    FpSpread1.Features.RichClipboard = True
    
    'Adding camera shape by using IPictures.Paste method
    TestActiveSheet.Cells("A1:E7").Copy(True)       'Have to Copy with bool showUI = true
    TestActiveSheet.Pictures.Paste("D11", True)     'Camera Shape refers to Sheet1!$A$1:$E$7 is created
    TestActiveSheet.Pictures.Paste("F11", False)    'A picture that snap content of A1:E7 is created 
    
    'Changing a picture to camera shape
    Dim picture As IShape = TestActiveSheet.Shapes.AddPictureToCell(Nothing, True, True, 1, 3)
    picture.Formula = "A1:E7"
    TestWorkBook.Names.Add("_name", "$A$1:$B$1")
    Dim picture1 As IShape = TestActiveSheet.Shapes.AddPictureToCell(Nothing, True, True, 6, 0)
    picture1.Formula = "_name"
    
    Note: Set fill doesn't have an effect on the enhanced camera shape.

    Recursive Painting in Camera Shape

    An enhanced camera shape is capable of being displayed inside another camera shape. Unlike Excel, camera shapes in Spread for Winforms do not display inside itself or another camera shapes if they create a recursive painting.

    You can observe the different behaviors in the examples below:

    Camera Shape with ExcelIO

    The enhanced camera shape is imported if EnhancedShapeEngine is true. Otherwise, the old camera shape is imported.

    When exporting camera shapes to Excel:

    Usage Scenario

    Consider a scenario where the sales data of different products across a supermarket is maintained to analyze the sales trends. The data for different product categories like Fruits, Vegetables, Bakery, Meat, etc., is managed in worksheets of a spreadsheet.

    You can display the summarized monthly sales data on a consolidated 'Dashboard' worksheet which shows camera shapes for the products' sales across different product categories. Any change made to the sales data is reflected in the 'Dashboard' sheet as well.

    C#
    Copy Code
    // Set header data in row 0 of Dashboard sheet and its setting
    sheetDashboard.Cells[0, 0].Text = "Monthly Trend Analysis";
    sheetDashboard.AddSpanCell(0, 0, 1, 14);
    // Set style for header text
    // Get range
    range = worksheet0.Cells["A1:A14"];
    // Apply style to range
    range.Font.ApplyFont(new GrapeCity.Spreadsheet.Font() { Name = "Arial", Size = 12, Bold = true });
    range.VerticalAlignment = GrapeCity.Spreadsheet.VerticalAlignment.Center;
    range.HorizontalAlignment = GrapeCity.Spreadsheet.HorizontalAlignment.Center;
    worksheet0.Cells[0, 0].Interior.Color = GrapeCity.Spreadsheet.Color.FromArgb(unchecked((int)0xFF8CA4B9));
    
    // Add camera shapes in Dashboard sheet
    worksheet1.Cells["A1:C8"].Copy(true);   // Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("A3", true);  // CameraShape refers to worksheet1!$A$1:$C$8 is created
    
    worksheet2.Cells["A1:C7"].Copy(true);   // Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("H3", true);  // CameraShape refers to worksheet2!$A$1:$C$7 is created
    
    worksheet3.Cells["A1:C6"].Copy(true);   // Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("A17", true); // CameraShape refers to worksheet2!$A$1:$C$5 is created
    
    worksheet4.Cells["A1:C8"].Copy(true);   // Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("H17", true); // CameraShape refers to worksheet2!$A$1:$C$8 is created
    
    // Set activesheet to dashboard sheet
    fpSpread1.ActiveSheetIndex = 0;
    
    Visual Basic
    Copy Code
    'Set header data in row 0 of Dashboard sheet and its setting
    sheetDashboard.Cells(0, 0).Text = "Monthly Trend Analysis"
    sheetDashboard.AddSpanCell(0, 0, 1, 14)
    'Set style for header text
    'Get range
    range = worksheet0.Cells("A1:A14")
    'Apply style to range
    range.Font.ApplyFont(New GrapeCity.Spreadsheet.Font() With {
        .Name = "Arial",
        .Size = 12,
        .Bold = True
    })
    range.VerticalAlignment = GrapeCity.Spreadsheet.VerticalAlignment.Center
    range.HorizontalAlignment = GrapeCity.Spreadsheet.HorizontalAlignment.Center
    worksheet0.Cells(0, 0).Interior.Color = GrapeCity.Spreadsheet.Color.FromArgb(&HFF8CA4B9)
    
    'Add camera shapes in Dashboard sheet
    worksheet1.Cells("A1:C8").Copy(True)    'Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("A3", True)   'CameraShape refers to worksheet1!$A$1:$C$8 is created
    
    worksheet2.Cells("A1:C7").Copy(True)    'Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("H3", True)   'CameraShape refers to worksheet1!$A$1:$C$7 is created
    
    worksheet3.Cells("A1:C6").Copy(True)    'Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("A17", True)  'CameraShape refers to worksheet1!$A$1:$C$5 is created
    
    worksheet4.Cells("A1:C8").Copy(True)    'Have to Copy with bool showUI = true
    worksheet0.Pictures.Paste("H17", True)  'CameraShape refers to worksheet1!$A$1:$C$8 is created
    
    'Set activesheet to dashboard sheet
    FpSpread1.ActiveSheetIndex = 0
    
    Note: You must update camera shape manually if the source data is modified using the FarPoint namespace. The following APIs can be used to refresh the enhanced camera shape:
    • IWorksheet.Pictures.Refresh - Re-paints all camera shape in the worksheet.
    • CalculationEngine.NotifyVisualChanged - Notifies the calculation engine that the visuals are repainted.

    Creating a Custom Camera

    Spread for Winforms provides the ICamera interface that represents the visual of a cell range in a single cell. You can use the following ICamera members:

    The following GIF illustrates a custom CAMERA function that you can apply in cells. The function is used to show a cell range inside a cell.

     

    Show Code

    You can create the CAMERA function shown above by following the code below.

    C#
    Copy Code
    public partial class CameraShapeInterface : Form
    {
        public CameraShapeInterface()
        {
            InitializeComponent();
        }
    
        private void CameraShapeInterface_Load(object sender, EventArgs e)
        {
            fpSpread1.AddCustomFunction(new CameraFunction());
            IWorkbook workbook = fpSpread1.AsWorkbook();
            workbook.Worksheets.Add();
            IWorksheet sheet2 = workbook.Worksheets[1];
            sheet2.Cells["B2"].Value = 5;
    
            IWorksheet sheet1 = workbook.Worksheets[0];
            sheet1.Cells["A1"].ColumnWidth = sheet2.Cells["A1"].ColumnWidth * 2 + 1;
            sheet1.Cells["A1"].RowHeight = sheet2.Cells["A1"].RowHeight * 2 + 1;
            sheet1.Cells["A1"].Formula = "CAMERA(Sheet2!A1:B2)";
        }
    }
    public class CameraFunction : VisualFunction
    {
        public CameraFunction() : base("CAMERA", 1, 1, FunctionAttributes.Variant, (IFunctionVisualizer)CameraVisualizer.Instance, false)
        {
    
        }
    
        protected override bool IsArrayParameter(int argIndex)
        {
            return true;
        }
    
        protected override bool Evaluate(IArguments arguments, IValue result)
        {
            IEvaluationContext context = arguments.EvaluationContext;
            IValue range = arguments[0];
            switch (range.ValueType)
            {
                case GrapeCity.CalcEngine.ValueType.Reference:
                case GrapeCity.CalcEngine.ValueType.AdjustableReference:
                    if (range.GetReferenceSource(context) is GrapeCity.Spreadsheet.IWorksheet worksheet)
                    {
                        ICamera camera = worksheet.Range(range.GetReference(context)).CreateCamera();
                        VisualizationData data = new VisualizationData(camera);
                        result.SetValue(data, true);
                        break;
                    }
                    else
                    {
                        goto default;
                    }
                default:
                    context.Error = CalcError.Reference;
                    break;
            }
    
            return true;
        }
    
        private class CameraVisualizer : FunctionVisualizer
        {
            internal static CameraVisualizer Instance;
    
            static CameraVisualizer()
            {
                Instance = new CameraVisualizer();
            }
    
            private CameraVisualizer()
            {
    
            }
    
            public override bool IsVisual => true;
            public override bool IsBackgroundSupported => true;
    
            protected override void PaintCell(IPaintingContext context, Rectangle rect, object cellValue, ref StyleFormat styleFormat)
            {
                if (cellValue is VisualizationData data && data.Value.ValueType == GrapeCity.CalcEngine.ValueType.Object && data.Value.GetObject() is ICamera camera)
                {
                    GrapeCity.Drawing.ImageBrush imageBrush = camera.Image;
                    if (imageBrush != null)
                    {
                        Brush brush = context.ToGdiBrush(imageBrush, rect);
                        context.Graphics.FillRectangle(brush, rect);
                        brush.Dispose();
                    }
                }
            }
        }
    }
    
    Visual Basic
    Copy Code
    Public Class CameraShapeInterface
        Private Sub CameraShapeInterface_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            FpSpread1.AddCustomFunction(New CameraFunction())
            Dim workbook As IWorkbook = FpSpread1.AsWorkbook()
            workbook.Worksheets.Add()
            Dim sheet2 As IWorksheet = workbook.Worksheets(1)
            sheet2.Cells("B2").Value = 5
            Dim sheet1 As IWorksheet = workbook.Worksheets(0)
            sheet1.Cells("A1").ColumnWidth = sheet2.Cells("A1").ColumnWidth * 2 + 1
            sheet1.Cells("A1").RowHeight = sheet2.Cells("A1").RowHeight * 2 + 1
            sheet1.Cells("A1").Formula = "CAMERA(Sheet2!A1:B2)"
    
        End Sub
    End Class
    
    Public Class CameraFunction
        Inherits VisualFunction
    
        Public Sub New()
            MyBase.New("CAMERA", 1, 1, FunctionAttributes.[Variant], CType(CameraVisualizer.Instance, IFunctionVisualizer), False)
        End Sub
    
        Protected Overrides Function IsArrayParameter(ByVal argIndex As Integer) As Boolean
            Return True
        End Function
    
        <Obsolete>
        Protected Overrides Function Evaluate(ByVal arguments As IArguments, ByVal result As IValue) As Boolean
            Dim context As IEvaluationContext = arguments.EvaluationContext
            Dim range As IValue = arguments(0)
            Dim worksheet As IWorksheet = Nothing
    
            Select Case range.ValueType
                Case ValueType.Reference, ValueType.AdjustableReference
    
                    If CSharpImpl.__Assign(worksheet, TryCast(range.GetReferenceSource(context), IWorksheet)) IsNot Nothing Then
                        Dim camera As ICamera = worksheet.Range(range.GetReference(context)).CreateCamera()
                        Dim data As VisualizationData = New VisualizationData(camera)
                        result.SetValue(data, True)
                        Exit Select
                    Else
                        GoTo _Select0_CaseDefault
                    End If
    
                Case Else
    _Select0_CaseDefault:
                    context.[Error] = CalcError.Reference
            End Select
    
            Return True
        End Function
    
        Private Class CameraVisualizer
            Inherits FunctionVisualizer
    
            Friend Shared Instance As CameraVisualizer
    
            Shared Sub New()
                Instance = New CameraVisualizer()
            End Sub
    
            Private Sub New()
            End Sub
    
            Public Overrides ReadOnly Property IsVisual As Boolean
                Get
                    Return True
                End Get
            End Property
    
            Public Overrides ReadOnly Property IsBackgroundSupported As Boolean
                Get
                    Return True
                End Get
            End Property
    
            <Obsolete>
            Protected Overrides Sub PaintCell(ByVal context As IPaintingContext, ByVal rect As Rectangle, ByVal cellValue As Object, ByRef styleFormat As StyleFormat)
                Dim data As VisualizationData = Nothing, camera As ICamera = Nothing
    
                If CSharpImpl.__Assign(data, TryCast(cellValue, VisualizationData)) IsNot Nothing AndAlso data.Value.ValueType = GrapeCity.CalcEngine.ValueType.Object AndAlso CSharpImpl.__Assign(camera, TryCast(data.Value.GetObject(), ICamera)) IsNot Nothing Then
                    Dim imageBrush As GrapeCity.Drawing.ImageBrush = camera.Image
    
                    If imageBrush IsNot Nothing Then
                        Dim brush As Brush = context.ToGdiBrush(imageBrush, rect)
                        context.Graphics.FillRectangle(brush, rect)
                        brush.Dispose()
                    End If
                End If
            End Sub
    
            Private Class CSharpImpl
                <Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
                Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
                    target = value
                    Return value
                End Function
            End Class
        End Class
    
        Private Class CSharpImpl
            <Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
            Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
                target = value
                Return value
            End Function
        End Class
    End Class
    

    Using the Spread Designer

    1. Enable EnhancedShapeEngine from the Spread property side pane.
    2. Select a block of cells in the designer.
    3. Select the Insert menu.
    4. Select the camera shape icon.
    5. Click on the shape to move it.
    6. The Shape Format menu with additional options is displayed.
    7. From the File menu choose Apply and Exit to apply your changes to the component and exit Spread Designer.