Search code examples
c#interopvisioflowchart

How to get the color of a shape object in MS Visio through C#


I have a shape object drawn as a 'group' such that the two sub-shapes are direct children of the group. All the shapes in the group have distinguishing colors.

I wish to know what is that property which can help me to get the color of the shape objects (Red, Green, White).

I know that shape has style property (Shape.Style) but that does not gives me the color value.

enter image description here

Application visApp = new Application();

Document visDoc = visApp.Documents.Open(VisiofilePath);

var shp = visApp.ActivePage.Shapes.ItemFromID[1];

string shapeColor = string.Empty;

foreach (Visio.Shape s in shp.Shapes)
{
    if(s.Text == "Child Object 1")
     {
        //shapeColor = 
     }

     if(s.Text == "Child Object 2")
     {
        //shapeColor = 
     }        
}

Any help will be much appreciated.


Solution

  • Getting hold of the fill color is not impacted by whether the shape is part of a group or not. Once you've got a reference to the right shape then you can look at the respective cells.

    Visio has two main methods of setting the fill color - Pattern fill and Gradient fill. The latter is from 2013 onwards.

    For Pattern fill, you're looking at three cells: FillForegnd, FillBkgnd and FillPattern. Most shapes start off with a solid fill (FillPattern 1) and this means that only the FillForegnd is used. For other pattern types you're dealing with both FillForegnd and FillBkgnd.

    For Gradient fill the FillGradientEnabled cell is set to 1 and this results in the Fill Gradient Stops section taking precedents.

    In the background, Visio maintains a Document.Colors collection. Some built-in colors can be accessed by index: 0 = black, 1 = white, 2 = red, 3 = green etc all the way up to 23. Any additional custom colors used are added to the collection and are also given an index. This means that, given an index, you can look up the color instance in the Colors collection.

    Following is some code to demo how to access the various types of coloring. Given these four shapes:

    enter image description here

    The first 3 shapes use Pattern fill, while the last uses Gradient fill.

    • Sheet.1 uses an index cell formula (3),
    • Sheet.2 uses an RGB function,
    • Sheet.3 uses a Pattern (2) and so uses both Foreground and Background cells
    • Sheet.4 uses Gradient stops and so Foreground and Background cells are ignored

    ... you could use the following code to read the colors at work (note this is using LINQPad as the output window makes it clearer to see what's going on:

    void Main()
    {
        var vApp = MyExtensions.GetRunningVisio();
    
        for (int i = 1; i <= 4; i++)
        {
            var shp = vApp.ActivePage.Shapes.ItemFromID[i];
            var colorInfos = new List<ColorInfo>();
            colorInfos.Add(new ColorInfo(shp.CellsU["FillForegnd"]));
            colorInfos.Add(new ColorInfo(shp.CellsU["FillBkgnd"]));
            new
            {
                shp.NameID,
                FillPattern = shp.CellsU["FillPattern"].ResultIU,
                FillGradientEnabled = Convert.ToBoolean(shp.CellsU["FillGradientEnabled"].ResultIU),
                PatternColors = colorInfos,
                GradientColors = FillGradientColors(shp) ?? "Default (10 stops all white)"
            }.Dump();
        }
    }
    
    private dynamic FillGradientColors(Visio.Shape shp)
    {
        List<string> rgbs = null;
        var iSect = (short)Visio.VisSectionIndices.visSectionFillGradientStops;
        for (int i = 0; i < shp.RowCount[iSect]; i++)
        {
            var targetCell = shp.CellsSRC[iSect, (short)i, (short)Visio.VisCellIndices.visGradientStopColor];
            if (targetCell.IsInherited == 0)
            {
                if (rgbs is null)
                {
                    rgbs = new List<string>();
                }
                rgbs.Add(ColorInfo.RgbString(targetCell));
            }
        }   
        return rgbs;    
    }
    
    
    public class ColorInfo
    {
        private Visio.Cell _vCell;
    
        public ColorInfo(Visio.Cell vCell)
        {
            _vCell = vCell;
            RGB = RgbString(_vCell);
        }
    
        public string Name => _vCell.Name;
        public string RGB { get; set; }
        public string FormulaU => _vCell.FormulaU;
    
        public static string RgbString(Visio.Cell cell)
        {
            var colorIdx = cell.Result[(short)Visio.VisUnitCodes.visUnitsColor];
            var c = cell.Document.Colors.Item16[(short)colorIdx];
            return $"RGB({c.Red},{c.Green},{c.Blue})";
        }
    }
    

    ... this produces the following output:

    enter image description here