Skip to main content
Home Forums Silverlight Programming Report a Silverlight Bug VisualStateManager does not execute complete event on switching tabs
0 replies. Latest Post by DavidGrayWright on November 4, 2009.
(0)
DavidGra...
Member
0 points
3 Posts
11-04-2009 11:45 PM |
I have a LOB application using an Accordion. The Accordion is programmatically populated as the async data returns from the web service request. The tab named "XAML Based" contains a XAML based Accordion and the tab with header “Dynamic” contains a dynamically created Accordion. On clicking "Toggle Selected Property on AccordionItems and Select Tab" I tried to emulate what a user is doing while the visual state is changing. You will need to click on "Create Accordion" first if you are on the “Dynamic” tab. If you click on "Toggle Selected Property on AccordionItems and Select Tab" in the “XAML Based” tab you will note the icons are pointing the wrong way however clicking the AccordItem causes a correction.If you click on "Toggle Selected Property on AccordionItems and Select Tab" in the “Dynamic” tab you will note on clicking the AccordionItem the grid does not appear. If you follow the debug output (which should be in your output window in Visual Studio) you will note there is *no* “Expand Completed” or “Collapse Completed” output which should match the vsg_CurrentStateChanging methods output. For example the output is... CurrentStateChanging Accordion 1NewState = Expanded Oldstate = Collapsed Putting a break point in Inspect_Accordion and inspecting the AccordionItems shows you that at least one of the items thinks it is _isBusyWithAction is set to true (normally the first item) this bool is set to false in OnStoryboardCompleted in the AccordionItem? I think this may be my path to salvation – can anyone help? NOTE: The LOB app does *not* have 10,000 items in it there are about 5 per accordion item – however if you decrease the number (c_AccordionItemItems) to say 10 – it is harder to reproduce – you may need to click the "Toggle Selected Property on AccordionItems and Select Tab" more than once.
MainPage.xaml.cs
1 using System.Windows; 2 using System.Windows.Controls; 3 4 namespace AccordionItemVisualState 5 { 6 public partial class MainPage : UserControl 7 { 8 private static int c_AccordionItemItems = 10000; 9 10 public MainPage( ) 11 { 12 InitializeComponent( ); 13 14 Loaded += new RoutedEventHandler( MainPage_Loaded ); 15 } 16 17 void MainPage_Loaded( object sender, RoutedEventArgs e ) 18 { 19 Populate( TestAccordion ); 20 } 21 22 private void Populate( Accordion _Accordion ) 23 { 24 Populate( _Accordion.Items[ 0 ] as AccordionItem ); 25 Populate( _Accordion.Items[ 1 ] as AccordionItem ); 26 Populate( _Accordion.Items[ 2 ] as AccordionItem ); 27 } 28 29 private void Populate( AccordionItem _AccordionItem ) 30 { 31 Grid aGrid = new Grid( ); 32 aGrid.ColumnDefinitions.Add( new ColumnDefinition( ) ); 33 _AccordionItem.Content = aGrid; 34 for( int i = 0; i < c_AccordionItemItems ; i++ ) 35 { 36 aGrid.RowDefinitions.Add( new RowDefinition( ) ); 37 TextBlock textBlock = new TextBlock( ) { Text = i.ToString( ) }; 38 textBlock.SetValue( Grid.RowProperty, i ); 39 textBlock.SetValue( Grid.ColumnProperty, 0 ); 40 aGrid.Children.Add( textBlock ); 41 } 42 } 43 44 private void Show_Accordion1( object sender, RoutedEventArgs e ) 45 { 46 TestAccordion.Visibility = Visibility.Visible; 47 } 48 49 private void Hide_Accordion1( object sender, RoutedEventArgs e ) 50 { 51 TestAccordion.Visibility = Visibility.Collapsed; 52 } 53 54 Accordion CreateDestroyAccordion = null; 55 56 private void Create_Accordion( object sender, RoutedEventArgs e ) 57 { 58 CreateDestroyAccordion = new Accordion( ); 59 CreateGrid.Content = CreateDestroyAccordion; 60 61 CreateGrid.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; 62 CreateGrid.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; 63 64 CreateDestroyAccordion.SelectionMode = AccordionSelectionMode.ZeroOrMore; 65 CreateDestroyAccordion.SelectionSequence = SelectionSequence.CollapseBeforeExpand; 66 CreateDestroyAccordion.HorizontalContentAlignment = HorizontalAlignment.Stretch; 67 68 CreateAccordionItem( CreateDestroyAccordion, "Accordion 1" ); 69 CreateAccordionItem( CreateDestroyAccordion, "Accordion 2" ); 70 CreateAccordionItem( CreateDestroyAccordion, "Accordion 3" ); 71 } 72 73 private void CreateAccordionItem( Accordion _Accordion, string _Header ) 74 { 75 AccordionItem_Fail accordionItem = new AccordionItem_Fail( ) { Header = _Header }; 76 _Accordion.Items.Add( accordionItem ); 77 Populate( accordionItem ); 78 } 79 80 private void Destroy_Accordion( object sender, RoutedEventArgs e ) 81 { 82 CreateDestroyAccordion = null; 83 CreateGrid.Content = null; 84 } 85 86 private void Inspect_Accordion( object sender, RoutedEventArgs e ) 87 { 88 if( CreateDestroyAccordion != null ) 89 { 90 AccordionItem_Fail accordionItem_Fail1 = CreateDestroyAccordion.Items[ 0 ] as AccordionItem_Fail; 91 AccordionItem_Fail accordionItem_Fail2 = CreateDestroyAccordion.Items[ 1 ] as AccordionItem_Fail; 92 AccordionItem_Fail accordionItem_Fail3 = CreateDestroyAccordion.Items[ 2 ] as AccordionItem_Fail; 93 } 94 } 95 96 private void Toggle_Accordion( object sender, RoutedEventArgs e ) 97 { 98 if( CreateDestroyAccordion != null ) 99 { 100 ToggleSelectedPropertyAndSelectTab( CreateDestroyAccordion, 0 ); 101 } 102 } 103 104 private void Toggle_Hide_Test_Accordion( object sender, RoutedEventArgs e ) 105 { 106 ToggleSelection( TestAccordion, 0 ); 107 ToggleSelection( TestAccordion, 1 ); 108 ToggleSelection( TestAccordion, 2 ); 109 110 if( TestAccordion.Visibility == Visibility.Collapsed ) 111 { 112 TestAccordion.Dispatcher.BeginInvoke( ( ) => { TestAccordion.Visibility = Visibility.Visible; } ); 113 } 114 else 115 { 116 TestAccordion.Dispatcher.BeginInvoke( ( ) => { TestAccordion.Visibility = Visibility.Collapsed; } ); 117 } 118 } 119 120 private void Toggle_Test_Accordion( object sender, RoutedEventArgs e ) 121 { 122 ToggleSelectedPropertyAndSelectTab( TestAccordion, 1 ); 123 } 124 125 private void ToggleSelectedPropertyAndSelectTab( Accordion _Accordion, int _TabIndex ) 126 { 127 ToggleSelection( _Accordion, 0 ); 128 ToggleSelection( _Accordion, 1 ); 129 ToggleSelection( _Accordion, 2 ); 130 131 /* 132 * Use Dispatcher to create a pause to allow storyboards to kick in!? 133 */ 134 135 _Accordion.Dispatcher.BeginInvoke( ( ) => { MainTabControl.SelectedIndex = _TabIndex; } ); 136 } 137 138 private void ToggleSelection( Accordion _Accordion, int _Index ) 139 { 140 AccordionItem accordionItem = _Accordion.Items[ _Index ] as AccordionItem; 141 accordionItem.IsSelected = !accordionItem.IsSelected; 142 } 143 } 144 } 145
MainPage.xaml
<UserControl x:Class="AccordionItemVisualState.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ex="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" xmlns:layoutPrimitivesToolkit="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Layout.Toolkit" xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit" xmlns:dgw="clr-namespace:AccordionItemVisualState" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"> <Grid x:Name="LayoutRoot"> <ex:TabControl x:Name="MainTabControl"> <ex:TabItem Header="XAML Based"> <StackPanel x:Name="TheStackPanel1" > <Button Content="Show Accordion" Click="Show_Accordion1"></Button> <Button Content="Hide Accordion" Click="Hide_Accordion1"></Button> <Button Content="Toggle Selected Property on AccordionItems and Select Tab" Click="Toggle_Test_Accordion"></Button> <Button Content="Toggle Selected Property on AccordionItems and Toggle Visibility Accordion" Click="Toggle_Hide_Test_Accordion"></Button> <Grid Background="Pink"> <layoutToolkit:Accordion SelectionMode="ZeroOrMore" x:Name="TestAccordion" Margin="10,10,10,10" HorizontalAlignment="Stretch" > <dgw:AccordionItem_Fail Content="Content - 1" Header="Header - 1"> </dgw:AccordionItem_Fail> <dgw:AccordionItem_Fail Content="Content - 2" Header="Header - 2"> </dgw:AccordionItem_Fail> <dgw:AccordionItem_Fail Content="Content - 3" Header="Header - 3"> </dgw:AccordionItem_Fail> </layoutToolkit:Accordion> </Grid> </StackPanel> </ex:TabItem> <ex:TabItem Header="Dynamic"> <StackPanel x:Name="TheStackPanel2" > <Button Content="Create Accordion" Click="Create_Accordion"></Button> <Button Content="Destroy Accordion" Click="Destroy_Accordion"></Button> <Button Content="Inspect Accordion" Click="Inspect_Accordion"></Button> <Button Content="Toggle Selected Property on AccordionItems and Select Tab" Click="Toggle_Accordion"></Button> <ScrollViewer Background="Pink" x:Name="CreateGrid"> </ScrollViewer> </StackPanel> </ex:TabItem> </ex:TabControl> </Grid> </UserControl>
AccordionItem_Fail.cs
1 using System; 2 using System.Linq; 3 using System.Windows; 4 using System.Windows.Controls; 5 using System.Windows.Media; 6 using System.Windows.Media.Animation; 7 using System.Collections; 8 using System.Collections.ObjectModel; 9 10 namespace AccordionItemVisualState 11 { 12 public class AccordionItem_Fail : AccordionItem 13 { 14 public override void OnApplyTemplate( ) 15 { 16 base.OnApplyTemplate( ); 17 18 FrameworkElement child = VisualTreeHelper.GetChild( this, 0 ) as FrameworkElement; 19 if( child != null ) 20 { 21 IList aList = VisualStateManager.GetVisualStateGroups( child ); 22 23 foreach( VisualStateGroup vsg in aList ) 24 { 25 if( vsg.Name.Equals( "ExpansionStates" ) ) 26 vsg.CurrentStateChanging += new EventHandler( vsg_CurrentStateChanging ); 27 } 28 } 29 if( VisualTreeHelper.GetChildrenCount( this ) > 0 ) 30 { 31 FrameworkElement root = VisualTreeHelper.GetChild( this, 0 ) as FrameworkElement; 32 33 if( root != null ) 34 { 35 Storyboard Fail_ExpandStoryboard = ( from stategroup in 36 ( VisualStateManager.GetVisualStateGroups( root ) as 37 Collection ) 38 where stategroup.Name == "ExpansionStates" 39 from state in ( stategroup.States as Collection ) 40 where state.Name == "Expanded" 41 select state.Storyboard ).FirstOrDefault( ); 42 43 Fail_ExpandStoryboard.Completed += new EventHandler( Fail_ExpandStoryboard_Completed ); 44 45 Storyboard Fail_CollapseStoryboard = ( from stategroup in 46 ( VisualStateManager.GetVisualStateGroups( root ) as 47 Collection ) 48 where stategroup.Name == "ExpansionStates" 49 from state in ( stategroup.States as Collection ) 50 where state.Name == "Collapsed" 51 select state.Storyboard ).FirstOrDefault( ); 52 53 Fail_CollapseStoryboard.Completed += new EventHandler( Fail_CollapseStoryboard_Completed ); 54 } 55 } 56 } 57 58 void Fail_CollapseStoryboard_Completed( object sender, EventArgs e ) 59 { 60 System.Diagnostics.Debug.WriteLine( "Collapse Completed" ); 61 } 62 63 void Fail_ExpandStoryboard_Completed( object sender /* Storyboard*/, EventArgs e ) 64 { 65 System.Diagnostics.Debug.WriteLine( "Expand Completed" ); 66 } 67 68 void vsg_CurrentStateChanging( object sender /* Grid */, VisualStateChangedEventArgs e ) 69 { 70 AccordionItem_Fail fail = ( e.Control as AccordionItem_Fail ); 71 System.Diagnostics.Debug.WriteLine( "CurrentStateChanging " + fail.Header.ToString( ) ); 72 if( e.NewState != null && e.OldState != null ) 73 System.Diagnostics.Debug.WriteLine( "NewState = " + e.NewState.Name + " Oldstate = " + e.OldState.Name ); 74 else 75 { 76 System.Diagnostics.Debug.WriteLine( "NewState = " + e.NewState.Name ); 77 } 78 } 79 } 80 } 81