15

I've got a control coded in WPF that can have one of three child elements - two SimpleChildElements and one ComplexChildElement, let's say - and swaps between display of them depending on some behind-the-scenes logic in the model that lets me do this.

<ItemsControl
   ItemsSource="{Binding ChildPanels.Values}" 
   Name="ContentControl1"
   >
   <ItemsControl.ItemTemplate>
     <DataTemplate>
       <ContentControl Content="{Binding}"
          Visibility="{Binding Path=Active, Converter={StaticResource BooleanToVisibilityConverter}}"/>
     </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>

The child elements are their own ViewModels and I've got some resources declared upstream so there are DataTemplates for them. I can elaborate more if it'll help, but the gripping element of the problem is this:

When I'm scrolling through elements in the master control and ComplexChildElement pops up for the first time, there's a brief, barely visible flicker as it gets decorated -- it's a bunch of combo boxes decorated with DevExpress. This setup means there's no flicker when I scroll off a record with a ComplexChildElement and back again, and if I start display of the master control with a ComplexChildElement there, there's no flicker when it pops up again.

But the master control is keyed to another data source, and I can't guarantee there will be a ComplexChildElement in the first record, which is loaded on initialize by a larger display framework I really don't want to root around in at the moment.

So how can I guarantee ComplexChildElement will get rendered when the form loads, and possibly hide it immediately after? I've already tried toggling ChildPanels.Active on and off inside the function behind this:

 <dxmvvm:Interaction.Triggers>
    <dxmvvm:EventToCommand EventName="Loaded" Command="{Binding OnViewLoadedCommand}" />
 </dxmvvm:Interaction.Triggers>

but that doesn't get them to render.

That function, by the way:

foreach (var childModel in ChildPanels.Values)
  {
    childModel.Active = true;
    RaisePropertyChanged(() => childModel.Active);
  }
ChangeChildModel();

with the last function call being the one called to change the child model visibility when the record changes. If I don't do that last call, all the child view models start out visible.

Glazius
  • 729
  • 7
  • 28
  • "I've already tried toggling ChildPanels.Active on and off inside the function behind this:...but that doesn't get them to render." I think that's a good place to pre-render the view. But why doesn't it show at all? – Tyress Dec 21 '15 at 06:53
  • IDK, though I added the function to the question itself. When I run things in debug mode and stick a breakpoint in the function, I don't actually see any visible UI elements when it's running, if that helps. – Glazius Dec 21 '15 at 16:56
  • What does ChangeChildModel() do? :) If you're disposing it you're not really pre-rendering it ,right? – Tyress Dec 22 '15 at 09:15
  • Just changes visibility by setting ChildModel.Active appropriately based on the current selected record. – Glazius Dec 22 '15 at 16:37
  • 1
    Is it not prudent to have the child models notify when they are loaded and handle their own behavior? Couldn't you then just have the child models in an observable collection and when the NotifyPropertyChanged is invoked in one of the child models in the collection, you fire the RaisePropertyChanged for the Loaded command in the parent? – Bryan Hobbs Dec 22 '15 at 23:33
  • Have you tested on other machines? Also, why bind to Visibility? You have control over the collection that is bound to the ItemsControl, why not use an `ICollectionView` to filter out the "not visible elements?" Also, does it need to be a `ContentControl`? Can you use `ItemsControl.ItemTemplateSelector` instead, does that help at all? One last thing I would try is defining the DataTemplates in `ContentControl.Resources` vs having it pull them in from higher level. – Kcvin Dec 23 '15 at 14:28

1 Answers1

3

Why not setting the Visibility to false right from the start? This doesn't prevent you from using the binding on Active afterwards.

Binding is OK, but as it is used by the DataTemplate to modify Visibility and by the parent control to know whether it should render the child control. So depending on the subscription order to the PropertyChanged event, the parent control may or may not see the control as Visible.

By the way, I'm wondering if your first goal was not to prevent flickering that may occurs when calling Show/Hide on several controls. I'm not sure pre rendering is the right fix for that.

Depending on the root cause of flickering, there are already several fixes on SO:

Community
  • 1
  • 1
Fab
  • 14,327
  • 5
  • 49
  • 68