【问题标题】:How to create Windows 8 style app bar in WPF?如何在 WPF 中创建 Windows 8 风格的应用栏?
【发布时间】:2012-10-13 09:19:54
【问题描述】:

我打算创建一个 Windows 8 Style App (Metro),但发现不支持使用双屏,这是我的应用程序的需求。

现在我正在将我的应用程序重新设计为 WPF 中的桌面应用程序。 但我仍然喜欢模仿 Windows 8 应用程序的一些不错的设计功能。

其中一个设计特点是通常在 Windows 8 风格的应用程序中使用的飞出栏:

  • 命令的底部应用栏
  • 顶部导航栏
  • 适用于所有应用的正确魅力

它们的共同设计是一个临时弹出面板,它位于当前窗口布局的顶部。

我的问题是:如何在 WPF 中创建类似的东西?

我可以毫无问题地创建一个带有隐藏底行的主网格,它可以显示一些常见的命令按钮。但是最好让它飞到我的标准布局之上,而不是挤压它。

我知道可以在当前窗口之上打开一个新窗口,但这会造成糟糕的代码设计并且很难看起来漂亮。我宁愿在同一个窗口中进行。

【问题讨论】:

    标签: wpf appbar


    【解决方案1】:

    很酷的问题!我最近实际上已经完成了魅力栏..

    理想情况下,您需要的是类似

    <Grid x:Name="LayoutRoot">
    
     <Grid x:Name="Overlay" Panel.ZIndex="1000" Visibility="Collapsed">
        <!-- This is where your slide out control is going to go -->
      </Grid>
    
      <!-- Use whatever layout you need -->
      <ContentControl x:Name="MainContent" />
    
    </Grid>
    

    现在不再挤压内容 - 叠加网格将位于其顶部,类似于魅力栏!全部使用 XAML

    如果您对此还有疑问,请给我留言!

    编辑;我的 Charm 实现 - 随意使用灵感!

    public class SlidePanel : ContentControl
        {
            static SlidePanel()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(SlidePanel), new FrameworkPropertyMetadata(typeof(SlidePanel)));
            }
    
            public SlidePanel()
            {
                EventManager.RegisterClassHandler(typeof(SlidePanel), SlidePanel.MouseEnterEvent,
                                                  new RoutedEventHandler(OnLocalMouseEnter));
    
                EventManager.RegisterClassHandler(typeof(SlidePanel), SlidePanel.MouseLeaveEvent,
                                                  new RoutedEventHandler(OnLocalMouseLeave));
            }
    
            #region Mouse Handlers
    
            private static void OnLocalMouseEnter(object sender, RoutedEventArgs e)
            {
                SetExpanded(sender, true);
            }
    
            private static void OnLocalMouseLeave(object sender, RoutedEventArgs e)
            {
                SetExpanded(sender, false);
    
            }
    
            private static void SetExpanded(object sender, bool expanded)
            {
                SlidePanel panel = sender as SlidePanel;
    
                if (panel != null)
                {
                    panel.IsExpanded = expanded;
                }
            }
    
            #endregion Mouse Handlers
    
            #region Panel Width
    
            public double PanelWidth
            {
                get { return (double)GetValue(PanelWidthProperty); }
                set { SetValue(PanelWidthProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for PanelWidth.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty PanelWidthProperty =
                DependencyProperty.Register("PanelWidth", typeof(double), typeof(SlidePanel), new UIPropertyMetadata(5.0));
    
            #endregion Panel Width
    
            #region Closed Width
    
            public double ClosedWidth
            {
                get { return (double)GetValue(ClosedWidthProperty); }
                set { SetValue(ClosedWidthProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for ClosedWidth.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty ClosedWidthProperty =
                DependencyProperty.Register("ClosedWidth", typeof(double), typeof(SlidePanel), new UIPropertyMetadata(5.0, new PropertyChangedCallback(OnClosedWidthChange)));
    
            #endregion Closed Width
    
            #region Expanded Property
    
            public bool IsExpanded
            {
                get { return (bool)GetValue(IsExpandedProperty); }
                set { SetValue(IsExpandedProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for IsExpanded.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsExpandedProperty =
                DependencyProperty.Register("IsExpanded", typeof(bool), typeof(SlidePanel), new UIPropertyMetadata(false, new PropertyChangedCallback(OnExpandedChanged)));
    
    
            #endregion Expanded Property
    
            #region Property Changes
    
            private static void OnExpandedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                if (e.NewValue == e.OldValue)
                    return;
    
                SlidePanel panel = d as SlidePanel;
    
                if (panel == null)
                    return;
    
                bool newVal = (bool)e.NewValue;
    
                panel.IsExpanded = newVal;
    
                bool expanded = (bool)panel.GetValue(IsExpandedProperty);
    
                Storyboard widthAnimation = AnimationHelper.CreateDoubleAnimation<SlidePanel>(panel, expanded,
                    (p, a) =>
                    {
                        a.From = (double)p.GetValue(SlidePanel.ClosedWidthProperty);
                        a.To = (double)p.GetValue(SlidePanel.PanelWidthProperty);
                    },
                    (p, a) =>
                    {
                        a.From = (double)p.GetValue(SlidePanel.WidthProperty);
                        a.To = (double)p.GetValue(SlidePanel.ClosedWidthProperty);
                    }, new TimeSpan(0, 0, 0, 0, 300), WidthProperty);
    
                Timeline opacity = AnimationHelper.DoubleAnimation(0.0, 1.0, expanded,
                                                                          new TimeSpan(0, 0, 0, 0, 300), OpacityProperty);
    
                Storyboard.SetTargetName(opacity, panel.Name);
    
                Storyboard.SetTargetProperty(opacity, new PropertyPath(OpacityProperty));
    
                widthAnimation.Children.Add(opacity);
    
                widthAnimation.Begin(panel);
    
            }
    
            private static void OnClosedWidthChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                SlidePanel panel = d as SlidePanel;
    
                if (panel != null)
                    panel.Width = (double)e.NewValue;
            }
    
            #endregion Property Changes
        }
    

    我发现的一个小技巧是在未展开时将不透明度设置为 0,但将宽度设置为 10,这样用户就可以将鼠标放在屏幕的一侧,然后它会在一秒钟后出现或者.. 干杯。

    编辑 - 根据要求.. AnimationHelper.

      public class AnimationHelper
        {
            public static Timeline DoubleAnimation(double from, double to, bool modifier, TimeSpan duration, DependencyProperty property)
            {
                DoubleAnimation animation = new DoubleAnimation();
    
                if (modifier)
                {
                    animation.From = from;
                    animation.To = to;
    
                }
                else
                {
                    animation.To = from;
                    animation.From = to;
                }
    
                animation.Duration = new Duration(duration);
    
                return animation;
            }
    
            public static Storyboard CreateDoubleAnimation<T>(T control, bool modifier, double from, double to, TimeSpan duration, DependencyProperty property) where T : Control
            {
                return
                 AnimationHelper.CreateDoubleAnimation<T>(control, modifier,
                    (p, a) =>
                    {
                        a.From = from;
                        a.To = to;
                    },
                    (p, a) =>
                    {
                        a.From = to;
                        a.To = from;
                    }, duration, property);
            }
    
            public static Storyboard CreateDoubleAnimation<T>(T control, bool modifier, Action<T, DoubleAnimation> onTrue, Action<T, DoubleAnimation> onFalse, TimeSpan duration, DependencyProperty property) where T : Control
            {
                if (control == null)
                    throw new ArgumentNullException("control");
    
                DoubleAnimation panelAnimation = new DoubleAnimation();
    
                if (modifier)
                {
                    if (onTrue != null)
                        onTrue.Invoke(control, panelAnimation);
    
                }
                else
                {
                    if (onFalse != null)
                        onFalse.Invoke(control, panelAnimation);
                }
    
    
                panelAnimation.Duration = new Duration(duration);
    
                Storyboard sb = new Storyboard();
    
                Storyboard.SetTargetName(panelAnimation, control.Name);
    
                Storyboard.SetTargetProperty(panelAnimation, new PropertyPath(property));
    
                sb.Children.Add(panelAnimation);
    
                return sb;
            }
        }
    

    【讨论】:

    • 感谢您的回答!!!实际上我非常接近......我尝试过 ZIndex 但没有让它工作。缺少的部分是对如何将子项添加到网格的简单误解。我认为您必须定义 ColumnDefinitions 和 RowDefinitions 才能使其正常工作。将子容器添加到主网格而不指定行或列会有所不同。我还发现不透明度和最小高度的建议非常有用。这很好地模仿了 Windows 8 应用风格。
    • @JakobLithner 太棒了!很高兴我能帮上忙!
    • 嗨,伙计们,我有点晚了,但我想知道您从哪里引用以下类/方法:AnimationHelper.CreateDoubleAnimation?我已经找了一些,但我能为该课程找到的只是一些第三方项目......
    • @KeithVinson 嘿,这是我当时写的一个类.. 没什么特别的,只是一个包装动画的类。据我记得,它只是包装了这个类msdn.microsoft.com/en-us/library/…
    • @DanSmith 我做了一些挖掘工作,终于找到了..查看答案:)
    猜你喜欢
    • 2013-09-06
    • 2014-03-26
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多