Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prerendering/hiding on load with WPF MVVM?

Tags:

c#

mvvm

wpf

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.

like image 729
Glazius Avatar asked Dec 15 '15 14:12

Glazius


1 Answers

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:

  • Control and/or its binding is recreated
  • PresentationSource disconnection
  • Work around to collapse control through Transparency
like image 132
Fab Avatar answered Nov 02 '22 08:11

Fab