GridSplitter behavior - c#

I am trying to add columns and gridsplitters to a grid, but can't get the exact behavior.
After the user specifies where he wants a vertical splitter to appear:
// Get current Col0 width, size new col and existing Col0
double col0Width = LayoutRoot.ColumnDefinitions[0].ActualWidth;
double newCol0Width = col0Width - 5 - pt.X;
LayoutRoot.ColumnDefinitions[0].Width = new GridLength(newCol0Width);
// New Column 0
var c = new ColumnDefinition();
c.Width = new GridLength(pt.X);
LayoutRoot.ColumnDefinitions.Insert(0, c);// Attach GridSplitter to left edge of existing first column
var gss = new GridSplitter();
gss.Background = new SolidColorBrush(Colors.DarkSlateBlue);
gss.Width = 5; gss.Cursor = Cursors.ScrollWE;
gss.ResizeBehavior = GridResizeBehavior.BasedOnAlignment;
gss.HorizontalAlignment = HorizontalAlignment.Left;
LayoutRoot.Children.Add(gss);
// Add to current left-most colunn
Grid.SetColumn(gss, 0);
// Create new column, insert
// New Column 0
var c = new ColumnDefinition();
c.Width = new GridLength(pt.X);
LayoutRoot.ColumnDefinitions.Insert(0, c);
// Move existing content from Col 0 to new Col 1.
I can repeat this and create an arbitrary number of vertical splitters.
The required resize behavior: moving a splitter resizes only the columns immed. to the left and right of the splitter.
The current resize behavior: moving a splitter treats everything to the right of the splitter as one object, expanding or shrinking the column to the left of the splitter, while moving everything to the right. That is, if there are 3 columns, moving the left-most splitter appears to push col 2 to the right and shrinking col 3, without resizing col 2.
(I hope I explained that clearly enough.)
I have tried putting the GridSplitters in their own columns, and tried various GridResizeBehaviors, but haven't found the correct combination.
Any tips would be appreciated....
And a related question: In an event handler for GridSplitter's OnDragDelta, is there a way to stop the splitter from traveling any further in a certain direction? I would like to prevent them from shrinking the right-most column below a certain width, while allowing them to move the splitter back to the left.
Thanks.

As my comment suggested, it looks like the columns need to be '*' sized.
So, after adding the new column and splitter, I fixed up the widths like this (first clumsy cut at solution):
// Get all col widths, set appropriate '*' sizes.
foreach (ColumnDefinition col in LayoutRoot.ColumnDefinitions)
{
colWidths.Add(col.Width);
total += col.Width.Value;
Debug.WriteLine($" Width : {col.Width}");
}
Debug.WriteLine($"{total}");
for (int i = 0; i < LayoutRoot.ColumnDefinitions.Count; i++)
{
double d = colWidths[i].Value;
double ratio = d / total;
int ii = (int) (ratio * 100);
LayoutRoot.ColumnDefinitions[i].Width = new GridLength(ii, GridUnitType.Star);
}

Related

C# TableLayoutPanel make all cells the same size

I need a TableLayoutPanel which should be able to change to different grids: 6x6, 10x10 and 16x16. The cells contain a PictureBox with black or white squares as images. Currently I have it where all cells are the same size except those in the last col and row. I am calculating and setting RowStyle to percent in code. E.g 16x16 is 6.25% per row and col.This is the current outcome.
private void AddRowAndCols(int rowColCount)
{
//default is 6x6 so do nothing
if (rowColCount == 6)
return;
else
{
//set row & col count
TlpGameBoard.RowCount = rowColCount;
TlpGameBoard.ColumnCount = rowColCount;
//Calc % each row and col should be
float rowColPercentage = CalculateRowColPercentages(rowColCount);
//clear all current row & col styles as these are still set to the default
TlpGameBoard.ColumnStyles.Clear();
TlpGameBoard.RowStyles.Clear();
//Add new row & col styles
for (int i = 0; i < rowColCount; i++)
{
TlpGameBoard.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, rowColPercentage));
TlpGameBoard.RowStyles.Add(new RowStyle(SizeType.Percent, rowColPercentage));
}
}
I am calculating the % by doing: 100F/numberOfRows as type Float.
The TLP Size is 800, 800.
I have also tried to implement the solution from
Creating same size cells with TableLayoutPanel however this is not working for me.
New to Stack Overflow and programming so apologies for any poor coding/posting practises.
Edit- how do I ensure the cells always stay equal size compared to each other no matter what grid they are? The size of the TLP need to stay the same too.
Thanks

ActiveReports 13 Vertical Text spacing

I am trying to vertically align text in ActiveReports 13. I am creating this report in code. The example I am trying to match is this:
However, after my efforts to do it, my result ends up looking like this:
The spacing seems to break at odd spots, even though the text in the data source is correct. The code I am using is:
for (int i = 0; i < dataTable.Columns.Count; i++)
{
ctl = new GrapeCity.ActiveReports.SectionReportModel.TextBox();
ctl.Name = columnName;
ctl.Text = dt.Columns[i].ColumnName;
ctl.Location = new PointF((0.3f * i) + 1.7f, 0.4f);
ctl.Size = new SizeF(0.3f, 1.0f);
ctl.VerticalText = true;
ctl.VerticalAlignment = GrapeCity.ActiveReports.Drawing.VerticalTextAlignment.Middle;
}
Increasing the width doesn't help. If I narrow the Size value and adjust the CharacterSpacings, the text spacing problem improves, but the background is narrowed and the text alignment shifts - the characters are rotated 90 degrees:
Any suggestions?
I found the way to solve this was to convert the TextBox to a Label, and then change the Angle property to 2700. Setting the Alignment to "Right" also aligned the text just how I wanted it:
ctl = new GrapeCity.ActiveReports.SectionReportModel.Label();
ctl.Angle = 2700;
ctl.Alignment = GrapeCity.ActiveReports.Drawing.TextAlignment.Right;

Horizontal position of two cells returns same result for cells in different columns in Word VSTO

I compared results of reading (x,y) coordinates of different cells for two different tables. For one, works perfectly fine - both x and y are correctly read, whereas for the second, x should be different but is the same for two cells. I am sure that I chose correct cells because their text is correct (also their height and width). Both tables have no empty cells and the indexes are correct. I've also tried the approach with selecting cell via Cell.Select() and then reading the vertical/horizontal position from selected range. The result's the same.
Code reading vertical and horizontal position of cell (for different values of index):
private ResultObject CreateresultObjectBasedOnTable(Table table, int cellIndex)
{
var resultObject = new ResultObject();
double DPIMultiplier = 200.0 / 220.0;
resultObject.y = table.Range.Cells[cellIndex].Range.
Information[WdInformation.wdVerticalPositionRelativeToPage] * DPIMultiplier;
resultObject.x = table.Range.Cells[cellIndex].Range.
Information[WdInformation.wdHorizontalPositionRelativeToPage] * DPIMultiplier;
resultObject.Height = table.Range.Cells[cellIndex].Height * DPIMultiplier;
resultObject.Width = table.Range.Cells[cellIndex].Width * DPIMultiplier;
return resultObject;
}
For first table in the attached picture, for cellIndex = 1, cellIndex = 2 and cellIndex = 3, the results vary. For the second table for cellIndex = 1, cellIndex = 2 and cellIndex = 3 resultObject.x is the same.

WPF Binding Without XAML

I have a WPF app with a "Grid Window". This window has no added XAML to it. I create a grid (columns and rows) then place a rectangle in each one all in C#.
This allows me to make a grid where I set the 'Stroke' and show locations on the grid when I set the 'Fill'.
The entire grid is set the same, in other words, if one part of the grid is red, the whole grid is red. Currently I set the grid by iterating through all of the rectangles and setting the 'Stroke' property. That works fine but seems very slow compared to most of the other operations. I would like to bind the stroke property to a variable in the C# (unless iterating is a reasonable way to handle it).
I have looked at quite a few questions here, but most want to use XAML. My code below is based off of Binding without XAML [WPF]. No errors, the grid just never shows up.
// put a rectangle in each square
for (int i = 0; i < x; i++) // for each column
{
for (int j = 0; j < y; j++) // for each row
{
// create a new rectangle with name, height, width, and starting color (transparent)
var rect = new Rectangle()
{
Name = $"rec{(i + 1).ToString("00")}{(j + 1).ToString("00")}", //column 5 row 2 -> rec0502
Height = squareSize,
Width = squareSize,
Fill = _ColorOff
};
// create the binding
var binder = new Binding
{
Source = _GridColor, // Brush that is updated on color change
Path = new PropertyPath("Stroke")
};
// apply the binding to the rectangle
rect.SetBinding(Rectangle.StrokeProperty, binder);
rect.DataContext = binder;
// place the rectangle
Grid.SetColumn(rect, i); // current column
Grid.SetRow(rect, (y - j - 1)); // same row but from the bottom (puts point 0,0 at bottom left)
// add the rectangle to the grid
grdBattleGrid.Children.Add(rect);
}
}
Even if iterating is fine, I'd still like to know what I'm doing wrong.
EDIT: The color name is chosen from a ComboBox on a separate window. This updates the user settings, which in turn throws an event my "Grid Window" is subscribed to. I convert the name to a SolidColorBrush before iterating though the rectangles.
The most simple solution would be not to have any Binding at all. Assign _GridColor to the Rectangle's Stroke. Whenever the Color property of (the assumed SolidColorBrush) _GridColor changes, it affects all Rectangles.
public SolidColorBrush _GridColor { get; } = new SolidColorBrush();
...
var rect = new Rectangle
{
Name = $"rec{(i + 1).ToString("00")}{(j + 1).ToString("00")}",
Height = squareSize,
Width = squareSize,
Fill = _ColorOff,
Stroke = _GridColor // here
};
Grid.SetColumn(rect, i);
Grid.SetRow(rect, (y - j - 1));
grdBattleGrid.Children.Add(rect);
Change the Rectangle Stroke by assigning a value to the Color property of the _GridColor Brush:
_GridColor.Color = Colors.Red;
You just need to set the DataContext one time for the Window, not for each Rectangle.
Is Binding your own view model class from INotifyPropertyChanged interface? Link to MS Docs

C# EPPLUS Chart SetPosition Method Row Offset does not work

I am creating a chart to export to excel. I need to create several, so I would offset them using the SetPosition() method with the 4 parameters:
SetPosition(int row, int rowoffset in pixel, int col, int coloffset in pixel)
thus
chart.SetPosition(startRow, 350*i, 0, 50);
The problem is that the second row offset parameter stretches the chart by 350*i pixels higher. This must be a bug since the col offset 4th parameter works fine and as expected.
I need to use startRow to start at a specific row cell in the sheet, so I need to get the row offset to work somehow.
Any ideas?
The RowOffset and ColumnOffset have given me trouble as well and I avoid using them in that function. If you look at the source could you can see it doing alot of match with the chart height/width so it seems to do more then just set and top/left position. I have not gone through the effort to fully reverse engineer it.
I just do the math myself. Knowing the default row height in pixels is the only thing that you have to watch out for since this can be customized by the user which you cannot know at design time Here is what I do:
using (var pck = new ExcelPackage(fi))
{
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromDataTable(datatable, true);
//Set specific values to make predictable
const int EXCELCHARTWIDTH = 375;
const int EXCELCHARTHEIGHT = 350;
//Have to assume a standard screen dpi but can be customized by the user
const double EXCELDEFAULTROWHEIGHT = 20.0;
var startCell = (ExcelRangeBase)worksheet.Cells["A1"];
for (var i = 0; i < 10; i++)
{
var chart = worksheet.Drawings.AddChart("chart " + i, eChartType.Pie);
chart.SetSize(EXCELCHARTWIDTH, EXCELCHARTHEIGHT);
chart.SetPosition(startCell.Start.Row, 0, startCell.Start.Column, 0);
var chartcellheight = (int)Math.Ceiling(EXCELCHARTHEIGHT / EXCELDEFAULTROWHEIGHT);
startCell = startCell.Offset(chartcellheight, 0);
}
pck.Save();
}
The offset is an offset within one cell.
So if you have a cell 64 x 20 pixels (default) it should not usually exceed 64 or 20 resp. To set the top left corner of a chart just in the middle of a cell, call:
chart.SetPosition(row , 10, col, 32);
also note that if you read the position from From.RowOff, you need to divide it by 9525

Categories