This project is read-only.
Visual State Manager

VisualStateManager.png

In regular XAML-based WPF, the Visual State Manager is commonly used now instead of Triggers to transform whole sets of properties of WPF Framework Elements in batch so to speak, or even to swap out whole UserControls (Views). Often, such state changes are paired with animated transitions.

In the Demo App, I provide an example of swapping out entire WPF Composites leveraging animated transitions. However, I must point out that often it is much easier to take the simple approach of merely changing properties on child controls within a Composite instead of swapping out an entire one. Yet, if this is something you would like to do, it is possible.

In the example below, I switch between two states: (1) Disabled State, and (2) Enabled State. However, instead of using a Visual State Manager, I merely remove an old Composite and add a new Composite, transferring any data from the old one to the new one. As part of this process, I provide a couple basic transitions using a combination of Rx and WPF Animations under-the-covers. These transitions are ScaleOutScaleIn and FadeOutFadeIn. Each transition takes an old element, a new one, a duration in seconds for the transition to last, and an action to perform at the end. In the action at the end, you can actually remove the old element since it has been completely scaled out or faded out, and you can also re-enable any button that was clicked since it is typically a good idea to temporarily disable the button that starts the transition while the transition is running.

I should note that each time the transition runs, I speed it up, up until a set maximum speed. I have merely heard that this is a good usability practice to give casual users a nice slow transition and power users who will be performing multiple actions within the application eventually very snappy transitions.

The example below uses the Boolean switchTransition to toggle between using the Scale transition or the Fade transition. In the real world, you'd likely just pick one or the other to use (or write your own custom transition.)

double counter = 3D;
bool switchTransition = false;
gpb.BeginSettings<GroupBox>()
                .SetItemBorderSettings(double.NaN, 400D, Brushes.Silver, new Thickness(0))
                .SubscribeEventOnParent("IsEnabledChanged", new DependencyPropertyChangedEventHandler((o, e) =>
                {
                    //mimmick something like the Visual State Manager
                    if (gpb.IsEnabled == false)
                    {
                        //1. DISABLED STATE
                        if ((counter - 0.3D) > 0.5D)
                        {
                            //make animation slightly faster each time down to half a second . . .
                            counter = counter - 0.3D;
                        }
                        Canvas myCanvas = gpb.GetChildFromParent<Canvas, GroupBox>(gxguid1, 0, 0);
                        
                        //unsubscribe any events if necessary
                        // myCanvas.UnsubscribeContainerEventByKey<Canvas>("GotFocus", cxanvGuid);
                        
                        Border oldComposite = myCanvas.GetCompositeFromParent(cxanvGuid);

                        string transferData1_1 = oldComposite.GetChildFromComposite<TextBox, Canvas>(1, 1).Text;
                        string transferData2_1 = oldComposite.GetChildFromComposite<TextBox, Canvas>(2, 1).Text;                 

                        myCanvas.SetBackgroundColor(Brushes.Silver);

                        //optionally change or add new settings on-the-fly . . .
                        //if(!myCanvas.ContainsFontSettingAtXY(2, 1))
                        //{
                        //     myCanvas.AddSetting<TextBlock, Canvas>(2, 1,"FontFamily", new FontFamily("Arial"));
                        //     myCanvas.AddSetting<TextBlock, Canvas>(2, 1,"FontSize", 11D);
                        //     myCanvas.AddSetting<TextBlock, Canvas>(2, 1,"FontWeight",  FontWeights.Bold);
                        //     myCanvas.AddSetting<TextBlock, Canvas>(2, 1,"FontStyle", FontStyles.Normal);
                        //}

                        //create the new composite
                        //transfer data so as to maintain data from prior composite
                        Border mynewComposite = myCanvas.BeginComposite(cxanvGuid2)

                          //since we are moving to the Disabled State, only add Text Blocks NOT Text Boxes  . . .
                          .AddText<Canvas>(0, 1, "This is a brand new Composite!")
                          .AddText<Canvas>(1, 0, "Attraction:")
                          .AddText<Canvas>(2, 0, "Location:")
                          .AddText<Canvas>(1, 1, transferData1_1)
                          .AddText<Canvas>(2, 1, transferData2_1)
                          .EndComposite<Canvas, CanvasArgs>(new CanvasArgs(0, 0, 0));

                        //optionally change or add even more properties on-the-fly . . .
                        mynewComposite.GetChildFromComposite<TextBlock, Canvas>(0, 1).SetValue(Grid.ColumnSpanProperty, 2); 
                        mynewComposite.GetChildFromComposite<TextBlock, Canvas>(1, 1).TextAlignment= TextAlignment.Left;
                        mynewComposite.GetChildFromComposite<TextBlock, Canvas>(2, 1).TextAlignment = TextAlignment.Left;
                        mynewComposite.GetChildFromComposite<TextBlock, Canvas>(1, 1).VerticalAlignment = VerticalAlignment.Center;
                        mynewComposite.GetChildFromComposite<TextBlock, Canvas>(2, 1).VerticalAlignment = VerticalAlignment.Center;

                        if (switchTransition)
                        {
                            oldComposite.ScaleOutScaleIn(mynewComposite, AnimationExt.ScaleType.RightToLeft, counter, () =>
                           {
                               if (myCanvas.IsCompositeOnParent(cxanvGuid))
                               {
                                   myCanvas.RemoveByKey(cxanvGuid);
                                   myCanvas.RemoveZIndexSetting<Border, Canvas>(0, 0);
                                   myCanvas.SetZIndex<Border, Canvas>(0, 0, 1); //re-set z-index on new visible composite

                                   //re-enable flatbutton after animation has fully completed
                                   this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 3).IsEnabled = true;
                                   this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 2).IsEnabled = true;
                           
                               }
                           }, oldComposite.GetParentFromComposite<Canvas>().GetContainerFromComposite<Grid, Canvas>(oldComposite), Colors.Gray, counter);
                        }
                        else
                        {
                            oldComposite.FadeOutFadeIn(mynewComposite, counter, () =>
                            {
                                if (myCanvas.IsCompositeOnParent(cxanvGuid))
                                {
                                    myCanvas.RemoveByKey(cxanvGuid);
                                    myCanvas.RemoveZIndexSetting<Border, Canvas>(0, 0);
                                    myCanvas.SetZIndex<Border, Canvas>(0, 0, 1); //re-set z-index on new visible composite

                                    //re-enable flatbutton after animation has fully completed
                                    this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 3).IsEnabled = true;
                                    this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 2).IsEnabled = true;
                           
                                }
                            });                        
                        }
                    }
                    else
                    {
                        //2. ENABLED STATE
                        if ((counter - 0.3D) > 0.5D)
                        {
                            //make animation slightly faster each time down to half a second . . .
                            counter = counter - 0.3D;
                        }

                        Canvas myCanvas = gpb.GetChildFromParent<Canvas, GroupBox>(gxguid1, 0, 0);

                        Border oldComposite = myCanvas.GetCompositeFromParent(cxanvGuid2);

                        string transferData1_1 = oldComposite.GetChildFromComposite<TextBlock, Canvas>(1, 1).GetText();
                        string transferData2_1 = oldComposite.GetChildFromComposite<TextBlock, Canvas>(2, 1).GetText();

                        myCanvas.SetBackgroundColor(Brushes.WhiteSmoke); //restore original color

                        Border mynewComposite = myCanvas.BeginComposite<Canvas>(cxanvGuid)

                              //since we are moving to the Enabled State, add TextBoxes . . .
                              .AddAnything<TextBox, Canvas>(1, 1)
                              .AddAnything<TextBox, Canvas>(2, 1)
                              .AddText<Canvas>(1, 0, "Attraction:")
                              .AddText<Canvas>(2, 0, "Location:")
                              .AddText<Canvas>(3, 0, "this is text at row 3 column 0")
                              .AddText<Canvas>(0, 0, "Arboretum")
                              .AddImage<Canvas>(0, 1, @"pack://siteoforigin:,,,/Images/woods.bmp", UriKind.Absolute, Double.NaN, 1, 1)
                              //.SubscribeEventOnContainer<Grid, Canvas>("GotFocus", new RoutedEventHandler(
                          //     (sender, e3) => { MessageBox.Show("GotFocus " + e3.Source.ToString()); }))
                              .SetColorOnContainer<Grid, Canvas>(Brushes.Transparent)
                              .SetMouseOverColorOnContainer<Grid, Canvas>(Brushes.LightYellow)                              
                              .EndComposite<Canvas, CanvasArgs>(new CanvasArgs(0, 0, 0));

                        mynewComposite.GetChildFromComposite<TextBox, Canvas>(1, 1).Text = transferData1_1;
                        mynewComposite.GetChildFromComposite<TextBox, Canvas>(2, 1).Text = transferData2_1;
                        if (switchTransition)
                        {
                            oldComposite.ScaleOutScaleIn(mynewComposite, AnimationExt.ScaleType.BottomToTop, counter, () =>
                           {
                               if (myCanvas.IsCompositeOnParent(cxanvGuid2))
                               {
                                   myCanvas.RemoveByKey(cxanvGuid2);
                                   myCanvas.RemoveZIndexSetting<Border, Canvas>(0, 0);
                                   myCanvas.SetZIndex<Border, Canvas>(0, 0, 1); //re-set z-index on new visible composite

                                   //re-enable flatbutton after animation has fully completed
                                   this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 3).IsEnabled = true;
                                   this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 2).IsEnabled = true;
                               }
                           }, oldComposite.GetParentFromComposite<Canvas>().GetContainerFromComposite<Grid, Canvas>(oldComposite), Colors.Gray, counter);
                        }
                        else
                        {
                            oldComposite.FadeOutFadeIn(mynewComposite, counter, () =>
                            {
                                if (myCanvas.IsCompositeOnParent(cxanvGuid2))
                                {
                                    myCanvas.RemoveByKey(cxanvGuid2);
                                    myCanvas.RemoveZIndexSetting<Border, Canvas>(0, 0);
                                    myCanvas.SetZIndex<Border, Canvas>(0, 0, 1); //re-set z-index on new visible composite

                                    //re-enable flatbutton after animation has fully completed
                                    this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 3).IsEnabled = true;
                                    this.GetCompositeFromParent(_userCtlGuid).GetChildFromComposite<Border, UserControl>(0, 2).IsEnabled = true;                           
                                }
                            });
                        }
   . . . . . .
                    }
                }))
.EndSettings<GroupBox>();

Last edited Jul 7, 2013 at 5:59 AM by stagathome0069, version 11

Comments

No comments yet.