Dynamic Grid Measurements in WPF - Rendering Controls - c#

I am working on a Drag and Drop Editor that is creating items and adding them dynamically to a WPF Canvas. For each item, it is creating a dynamic grid and addign that to the canvas. I need layout state information about each one of these grids as it is added so that I know its coordinates on the canvas. The problem I am having is that when I try to access the Height/ActualHeight/RenderedSize information of each of these Grids that I add, it always turns out to be 0. I am assuming that I might need to render the items so that the new state information is registered, but I am not quite sure how to do this. I have seen support through the InvalidateXXXX() methods that are provided, but I am not sure if/or which one I should be using. there is also an UpdateLayout() function, but I am not sure if this is what I need.
Here is the code that I have running through a loop and adding Grids, which represent LineItems in the Canvas.
/*Initialize Grid Layout*/
Grid newGrid = new Grid();
newGrid.MinHeight = 50;
newGrid.Width = PreviewWindow.ActualWidth;
newGrid.Background = Brushes.Beige;
newGrid.ShowGridLines = true;
/*Define Column Definitions*/
List<ColumnDefinition> columns = new List<ColumnDefinition>(fieldItemList.Count);
foreach (ColumnDefinition column in columns)
{
ColumnDefinition labelColumn = new ColumnDefinition();
newGrid.ColumnDefinitions.Add(labelColumn);
newGrid.ColumnDefinitions.Add(column);
}
/*Define Row Definitions*/
RowDefinition row = new RowDefinition();
newGrid.RowDefinitions.Add(row);
int colCount = 0;
for (int i = 0; i < fieldItemList.Count; i++)
{
FieldItem fieldItem = fieldItemList[i];
/*Initialize Example Label*/
Label label = new Label();
label.Content = fieldItem.Label;
Grid.SetRow(label, 0);
Grid.SetColumn(label, colCount);
newGrid.Children.Add(label);
/*Initialize Example Text Box*/
TextBox textBox = new TextBox();
Grid.SetRow(textBox, 0);
Grid.SetColumn(textBox, colCount + 1);
newGrid.Children.Add(textBox);
colCount++;
}
stackPanel.Children.Add(newGrid);
//I need to Access the Height of each of the grids here somehow
lastTop += (int)newGrid.ActualHeight ;
newGrid.InvalidateMeasure();
//Or InvalidateVisual(), or do I perform this on something else?
}
There is reference to a StackPanel, all of these Grids are being added to a stack panel, and they will eventuall be arranged by the coordinates(which I currently cannot grab). The problem is right now it is adding all these items to a list that will need to be sorted by the Top coordinate, but since the Top coordinate is 0, it will not sort correctly.

A few notes:
The StackPanel does not provide size Layout suggestions to its children, so the Grid will need to supply it's own Layout size. In order for this to work, you'll need to set the Row and Column sizes to "Auto" so that they expand to accommodate their contents. Even then, I'm not entirely sure if this works (usually you combine Auto with "*" rows or columns, rather than having all Auto columns, having them expand to a fixed or stretched overall Grid size.) The layout I've proposed here will behave a bit oddly, as it will dynamically resize columns based on the contents of the column text boxes; for instance, if you have no text in any row, you'll get zero width text boxes with only margin and border providing any size.
Once the StackPanel has had its children added, you'll need to call UpdateLayout on the StackPanel. This will cause it to compute the layout information for each of its children and then position them appropriately. This can become expensive if you keep adding grids dynamically, so fair warning.

Related

How to adjust the row size without resize column in ListView in .NET C#

I'm trying to have a text from a List View Item in a single row without resize the column size, something like textbox property "Multiline"
In the picture below the column "Descripcion" is adding "..." to the product description, instead of that I want all the description in one row.
Something Like:
Descripcion Precio
-------------------|-------
All the description|
in one single row | 80
-------------------|-------
Another item in one|
single row | 70
-------------------|-------
I just tried with something like this:
ListViewItem row = new ListViewItem();
row.ListView.Height = 30;
but row.Height throw me an exception, any idea how to do this?
In order to set the height you can use SmallImageList, here is an example :
private void SetHeight(ListView listView, int height)
{
ImageList imgLst = new ImageList();
imgLst.ImageSize = new Size(1, height);
listView.SmallImageList = imgLst;
}
Also to wrap your Column, you could use ObjectListView, it's an open source C# wrapper around a .NET ListView

WPF DataGrid editable cells with Items put directively

So, I have a DataGrid, that I want to manipulate programmatically a lot.
string[] values = new string[something.Count];
for (int i = 0; i < somethingElse.Count; i++)
{
if (condition)
values[i] = Data[i].ToString();
else
values[i] = "";
}
var style = new System.Windows.Style(typeof(DataGridRowHeader));
style.Setters.Add(new Setter(DataGridRowHeader.ContentProperty, Data[0].ToString()));
MyGrid.Items.Add(new DataGridRow()
{
HeaderStyle = style,
Item = values
});
This I do in a loop and I am able to fill in my grid with all the data I need.
Later, I am able to access cells, edit them, take their values, whatever I want and need.
However, when user wants to use the grid as you would in MS Excel, the cells are not editable.
So I went the other way and created a :
ObservableCollection<ObservableCollection<string>> gridData = new ObservableCollection<ObservableCollection<string>>();
//*** ... *** the gridData is filled in the same way, you can imagine
MyGrid.ItemsSource = gridData;
This does fill in the data perfectly the same way, more than that, the data are now editable.
But my custom row headers disappeared.
I need them, also, I do not think I want to use binding for row header values.
Can the first approach be somehow modified to still be editable, but rows with data being filled the very same way?
I eventually solved this combining both the abovementioned approaches.
First, I generate ObservableCollection<ObservableCollection<string>> dataCollection, fill it with data.
Next I generate an ObservableCollection<DataGridRow> rowCollection collection.
In my declarative part of the loop from the first approach, that you can see in the question, I do this
rowCollection.Add(new DataGridRow()
{
HeaderStyle = style,
Item = dataCollection[i] //for the corresponding iteration element
});
This all ends up when setting
MyGrid.ItemsSource = rowCollection;
Till now (very little time of testing), this seems to be what I was looking for, hope it might help someone else aswell.

changes to the children of the grid dynamically

I'm trying to implement a search suggestion feature using the grid view of Xamarin forms. I was wondering if there is anyway to change the children of the grid dynamically according to the text get entered in the search box.
grid.Children.Add(new Label
{
Text = x.Text,
TextColor = Color.White,
BackgroundColor = Color.Blue
}, 0, x.Id);
If you want to use Grid , then you should specify row ands colums, otherwise all the texts will overlaps each other. Instead of Grid, you should use StackLayout.
hintSL = new StackLayout(){
HorizontalOptions= LayoutOptions.Fill,
//Orientation = Vertical or Horizontal (however you want)
};
//if you want to add hintsSl into your grid
Grid.SetRow(hintsl, 4);
Grid.SetColumn(hintsl, 4);
searchText.Changed+=(s,e)=>{
hintSL.Children.Clear();
foreach(var hint in YourHintsList)
hintsl.Children.Add(new Label(){Text=hint, and other properties});
};
Here are two ways to do this:
The first is to use binding. Bind the text field of the label to a bindable property that changes according to the user's entry.
The second is to make the label a member of whatever class holds the grid, rather than anonymous. Then you can catch the event (eg OnEntryChanged) generated when the user enters the text and dynamically set the label in the code.

Microsoft Chart Control Axis Titles not displaying properly

I am having problems getting the XAxis to display the correct values in my chart control. Below is how I am generating each series to be displayed. I would like the XAxis to display the DataType value from s.DataType:
foreach (SummaryData s in summaryData)
{
System.Web.UI.DataVisualization.Charting.Series series = new System.Web.UI.DataVisualization.Charting.Series(s.DataType);
series.ChartType = System.Web.UI.DataVisualization.Charting.SeriesChartType.Column;
DataPoint dp = new DataPoint();
dp.Name = s.DataType;
dp.SetValueY(s.Total);
dp.SetCustomProperty("DataType", s.DataType);
series.XValueMember = "DataType";
series.Points.Add(dp);
msBarVertLegRight.Series.Add(series);
}
msBarVertLegRight.DataBind();
The corect value is displayed and the correct name in the Legend, but I'm not exactly sure how to set the XAxis value.
JH
Looks like you're trying to use databinding (which is what the XValueMember is for) and add points one by one. You can do one or the other. You could use databinding like so (approximately):
series.XValueMember = "DataType";
series.YValueMember = "ThePropertyWithY";
series.DataSource = s;
series.DataBind();
or you could set each point individually:
System.Web.UI.DataVisualization.Charting.Series series = new System.Web.UI.DataVisualization.Charting.Series("mySeries");
series.ChartType = System.Web.UI.DataVisualization.Charting.SeriesChartType.Column;
foreach (SummaryData s in summaryData)
{
series.AddXY(s.DataType, s.Total);
}
I'm not sure why you had each SummaryData.DataType being its own series; if that is needed, add that back in, but from the code you posted it didn't seem necessary.
When databinding, any changes to your underlying data (the SummaryData objects) will be reflected in your chart automatically; if you add points individually, you need to handle updates to your chart manually.

Add ToolStripMenuItem in new row when one row is filled inside ToolStrip

I have one form and inside form i have one toolstrip control, and i am adding ToolStripMenuItem dynamically.
What i want is when one is filled up, items should list in next row.
I tried this for increasing the height and width of form but adding items in new row not happening.
ToolStripItemCollection t_col = toolStripTaskBar.Items;
int _howMany = t_col.Count;
Rectangle mi_bounds = t_col[_howMany - 1].Bounds;
if (this.Width < (mi_bounds.X + mi_bounds.Width))
{
int minimumFormHeight = 80;
this.MinimumSize = new Size((mi_bounds.X + mi_bounds.Width), minimumFormHeight);
}
Let me know if you not understand what i want.
Any suggestion how can i achieve this.
Thank You.
You can use LayoutStyle property of ToolStrip. You need to set up it to Table and modify layout settings (specify rows and columns count).
You can do it like this:
this.toolStrip1.LayoutStyle = ToolStripLayoutStyle.Table;
var layoutSettings = (this.toolStrip1.LayoutSettings as TableLayoutSettings);
layoutSettings.ColumnCount = 3;
layoutSettings.RowCount = 3;
And the you can add new items to toolstrip:
var item = new ToolStripMenuItem(string.Format("item{0}", this.toolStrip1.Items.Count + 1));
this.toolStrip1.Items.Add(item);

Categories

Resources