Reputation: 53
I recently be confronted with WPF UI issue when trying to update ObservableCollection bind to a stackpanel.
I have a StackPanel in a WPF that contain custom UserControl. All these UIElement are in an ObservableCollection named "Parametres". I had them like this :
Parametres.Clear();
foreach(UIElement uie in SReference.UIEList)
{
Parametres.Add(uie);
}
When the method is called, I clear the old parameters ObservableCollection and directly set the new one.
There is no problems with that method except that when I change the parameters list for a new one quickly, the UI miss some of them. UI doesn't skip them, it seems skip the render
But when I change the UI size or refresh something, parameters suddenly appear
Is there a method for refreshing the UI or wait for UIElement render for every UIElement in my list ?
MORE DETAILS :
This application is plugin that allow user to create custom 3D Models inside a 3D design software. The goal is to cross inside different model reference and show to the user the parameters that can be edited inside the plugin.
I have an window that contain a ribbon and a main content section. This main content section change when necessary.
This is the main content section with who I have issues.
1- User choose a model category
2- User choose a product
3- User choose a standard reference or custom reference
4- User edit parameters
This model got many properties and some method like the one on the top. 3D model category is an ObservableCollection ComboBox content are bind to two ObservableCollection and the stackpanel that contain parameter is bind to an ObservableCollection
Every time you change something on step 1 2 or 3, ObservableCollection is clear and get (or not) some new element. There's element are generate by the main Model class.
Every UIElement in stackpanel are Custom UserControl. I have two type of these :
this is the code behind the "SReference.UIEList"
private List<UIElement> uieList;
public List<UIElement> UIEList
{
get
{
uieList.Clear();
// On ajoute tous les éléments d'interface dans la liste.
foreach(LengthParameterModelView parametre in parameters)
{
uieList.Add(parametre.lp);
}
string lastGroupeOption = "";
foreach (OptionParameterModelView option in options)
{
if(lastGroupeOption == "" || option.NomGroupe != lastGroupeOption)
{
lastGroupeOption = option.NomGroupe;
// Création du label du groupe d'options
Label l = new Label();
l.Margin = new Thickness(5, 0, 10, 0);
l.Style = ProduitAssocié.SousSectionUI.Resources["OptionLabel"] as Style;
l.Content = option.NomGroupe;
uieList.Add(l);
}
uieList.Add(option.ynp);
}
return uieList;
}
}
parametre.lp is UIElement generated by the ViewModel of length parameter
option.ynp is UIElement generated by the ViewModel of yes no parameter
Hope this will help.
Upvotes: 1
Views: 778
Reputation: 7908
You are most likely calling the code you showed while rendering the parent.
In this case, a situation may arise when the child elements have already been evaluated and they will not be redrawn until the next rendering.
Moving this code into a separate asynchronous task for the dispatcher is likely to help you.
Supplement.
If you are calling the method outside of Code Behind UserControl or Window, then you do not have a Dispatcher property.
Then you can get it from the application:
Dispatcher.BeginInvoke((Action)(() =>
{
Parametres.Clear();
foreach (UIElement uie in SReference.UIEList)
{
Parametres.Add(uie);
}
}));
I ran into a similar problem here: How to defeat a bug with Grid.Row / Column in ItemsPanelTemplate?
And a similar solution helped me.
Application.Current.Dispatcher.InvokeAsync(() =>
{
Parametres.Clear();
foreach (UIElement uie in SReference.UIEList)
{
Parametres.Add(uie);
}
});
Upvotes: 2