I´m kind of stuck here with a little problem. I´ve got a DataGrid whose ItemSource is fed by an ObservableCollection. (I´m creating a little plugin for Revit).
My ObservableCollection contains of some Elements which are created when doing a selection in Revit. It is my goal to create a Stackpanel with Textboxes, which do have the same height as the actualized Columnwidths, which are set to Auto.
When running the code in "normal" speed I get a result like this:

When I debug the whole process it runs slower and I get a result like this (Which I want to get without debug mode):

popup.DataGridSelectedObjects.UpdateLayout();
popup.DataGridSelectedObjects.Items.Refresh();
Thread.Sleep(2000)
public void AddRegexItemToStackpanel(string parameterName, DataGridColumn dc)
{
TextBox printTextBlock = new TextBox();
printTextBlock.Width = dc.ActualWidth;
printTextBlock.Margin = new Thickness(0.5, 0, 0, 0);
printTextBlock.Name = dc.Header.ToString().Replace("__", "_");
StackRegexPanel.Children.Add(printTextBlock);
}
Is there any method to wait the Observablecollection to update properly?
Thanks a lot and kind regards, Jannis
You should use a different approach. Using data binding should be the most intuitive. Avoiding XAML where XAML is possible will make life a lot harder most of the time and your code will start to smell.
Your
Thread.Sleeplooks very very suspicious too. It's also very likely that callingUpdateLayout()andItems.Refresh()should be avoided to improve the performance.Changing the data source (
ObservableCollection) will already trigger a refresh and, if necessary, a complete layout pass. No need to trigger both a second time. It will only make your UI slow.Below you find two examples: a static, hard-coded version and a more elegant and dynamic version (where text boxes are added automatically to match the column count).
Both examples will automatically adjust the width of each
TextBoxif columns are resized (as a bonus when using data binding). The examples also highlight the efficiency of data binding in WPF. Code will always become smelly and overly complex when avoiding data binding and XAML.To make a
TextBoxto follow the width of its respective column, simply use data binding:And to make it dynamic, simply use an
ItemsControlthat is configured to display its items horizontally:In both cases you should implement an
IValueConverterto convert fromdoubletoThickness(for theMargin) and bind theStackPanel.Marginof the first example or theItemsControl.Marginof the second example to theDataGrid.RowHeaderActualWidthproperty to adjust for the row header (to align the text boxes properly).Because you have provided more information, I felt the need to either delete or adjust my answer:
To dynamically change column count, you should always use a
DataTableas data source. I have added an extension method that converts a collection to aDataTable, in case you need it.Since the
TextBoxelements are meant to filter based on their associated column, I would suggest to modify theDataGrid.ColumnHeaderStyleto add aTextBoxto the column header. This will be more convenient as theTextBoxwill now automatically resize and move (in case the column is dragged).The column's
TextBoxwill bind to aObservableCollectionofstringvalues (filter expressions), where the index of each item maps directly to a column index. Handling theColectionChangedevent allows to handle theTextBoxinput.MainWindow.xaml.cs
MainWindow.xaml
Example to show how to modify the column header to add a
TextBoxand how to use the attached behavior. TheDataGridnow binds to aDataTablein order to allow to add/remove columns dynamically.DataGridColumnFilter.cs
Attached behavior to map the
TextBoxelements of the column headers to a collection (data source) - direction is one way and update is send onTextBox.LostFocus.My recommendation is to extend
DataGridto get rid of this attached behavior and to add more convenience to the control handling.If filtering is only view related (which is usually the case) i.e. you don't intend to modify the data source based on the filtering, I recommend to move the filtering logic to the attached behavior (or extended
DataGrid). This will keep your models clean.ExtensionMethods.cs
Extension method to convert a
IEnumerable<TData>to aDataTable.User.cs
The data model used to create the
DataTablefrom in the above example (MainWindow.xaml.cs). The class also gives an example on how to use the attributesIgnoreAttributeto controlthe visibility of properties/columns and
System.ComponentModel.DisplayNameto rename the property/column.IgnoreAttribute.cs