Win10开发:玩转应用窗体和应用标题栏TitleBar

Windows10 API允许开发者对应用窗体和应用标题栏做修改。


应用标题栏

先说应用标题栏吧,什么是应用标题栏?比如Groove音乐的应用标题栏就是下面这样:

   

什么,你说看不清楚。因为它是白色的,是微软设计的,这锅我不背。

你不喜欢怎么办?改呗!

Windows10 API提供解决方案,可以更改应用标题栏、右上方三个按钮、鼠标经过时按钮、鼠标按下时按钮、标题栏Inactive时、三个按钮Inactive时的前景色和背景色共12种属性颜色。(这里解释下Inactive,不知道怎么翻译合适,当应用置于你的眼前,在任务栏的应用图标上按住鼠标左键不放时就是Inactive状态,貌似是不可用的状态)

关于标题栏的MSDN看这:链接

什么,你说Edge浏览器的标题栏好像不太一样。没错,因为Edge把应用界面扩展至 Titlebar 的区域,所以看起来不一样。




下面简单的代码实现更改12种属性的颜色值:

  var titleBar = ApplicationView.GetForCurrentView().TitleBar;
            if (titleBar != null)
            {
                titleBar.BackgroundColor = Colors.Black;
                titleBar.ForegroundColor = Colors.White;
                titleBar.ButtonBackgroundColor = Colors.Brown;
                titleBar.ButtonForegroundColor = Colors.RoyalBlue;
                titleBar.ButtonPressedBackgroundColor = Colors.Green;
                titleBar.ButtonPressedForegroundColor = Colors.Orange;
                titleBar.ButtonHoverForegroundColor = Colors.Salmon;
                titleBar.ButtonHoverBackgroundColor = Colors.Blue;
                titleBar.InactiveForegroundColor = Colors.SpringGreen;
                titleBar.InactiveBackgroundColor = Colors.Red;
                titleBar.ButtonInactiveBackgroundColor = Colors.Tan;
                titleBar.ButtonInactiveForegroundColor = Colors.Violet;
            }
效果图

正常时:


鼠标滑过最大化按钮时:

鼠标按下最大化按钮时:


Inactive状态时:



如果要实现Edge浏览器的效果将应用界面扩展至 Titlebar 区域:

CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;

如果以上的修改你还不满意怎么办?不好意思你自己设计吧...

Windows 10允许开发者自定义标题栏控件,可以将界面中任意控件指定为标题栏,使用下面的函数

Window.Current.SetTitleBar(UIElement value);
其中value是一个自定义控件

官方的Demo(修改):自定义应用标题栏

首先需要自定义一个用户控件,也就是自定义的TtitleBar控件

XAML:

<Grid x:Name="RootGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Grid x:Name="TitleBar" VerticalAlignment="Top" Height="{x:Bind CoreTitleBarHeight, Mode=OneWay}" Canvas.ZIndex="3">
            <Rectangle x:Name="BackgroundElement" Fill="Green" />
            <Grid Padding="{x:Bind CoreTitleBarPadding, Mode=OneWay}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="TextBlock in Custom TitleBar"/>
                <CheckBox Grid.Column="1" Content="CheckBox in Custom TitleBar"/>
            </Grid>
        </Grid>
    </Grid>

最外层Grid分为两行是为了布局需要,Demo给了注释说明其作用:



C#代码部分稍微有点多,但都是逻辑很清晰的:

  public sealed partial class CustomTitleBar : UserControl, INotifyPropertyChanged
    {
        private CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar;

        public CustomTitleBar()
        {
            this.InitializeComponent();
            Loaded += CustomTitleBar_Loaded;
            Unloaded += CustomTitleBar_Unloaded;
        }

        void CustomTitleBar_Loaded(object sender, RoutedEventArgs e)
        {
            coreTitleBar.LayoutMetricsChanged += OnLayoutMetricsChanged;
            coreTitleBar.IsVisibleChanged += OnIsVisibleChanged;

            // The SizeChanged event is raised when the view enters or exits full screen mode.
            Window.Current.SizeChanged += OnWindowSizeChanged;

            UpdateLayoutMetrics();
            UpdatePositionAndVisibility();
        }

        void CustomTitleBar_Unloaded(object sender, RoutedEventArgs e)
        {
            coreTitleBar.LayoutMetricsChanged -= OnLayoutMetricsChanged;
            coreTitleBar.IsVisibleChanged -= OnIsVisibleChanged;
            Window.Current.SizeChanged -= OnWindowSizeChanged;
        }

        void OnLayoutMetricsChanged(CoreApplicationViewTitleBar sender, object e)
        {
            UpdateLayoutMetrics();
        }

        void UpdateLayoutMetrics()
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("CoreTitleBarHeight"));
                PropertyChanged(this, new PropertyChangedEventArgs("CoreTitleBarPadding"));
            }
        }

        void OnIsVisibleChanged(CoreApplicationViewTitleBar sender, object e)
        {
            UpdatePositionAndVisibility();
        }

        void OnWindowSizeChanged(object sender, WindowSizeChangedEventArgs e)
        {
            UpdatePositionAndVisibility();
        }

        void UpdatePositionAndVisibility()
        {
            if (ApplicationView.GetForCurrentView().IsFullScreenMode)
            {
                // In full screen mode, the title bar overlays the content. and might or might not be visible.
                TitleBar.Visibility = coreTitleBar.IsVisible ? Visibility.Visible : Visibility.Collapsed;
                Grid.SetRow(TitleBar, 1);
            }
            else
            {
                // When not in full screen mode, the title bar is visible and does not overlay content.
                TitleBar.Visibility = Visibility.Visible;
                Grid.SetRow(TitleBar, 0);
            }
        }

        UIElement pageContent = null;
        public UIElement SetPageContent(UIElement newContent)
        {
            UIElement oldContent = pageContent;
            if (oldContent != null)
            {
                pageContent = null;
                RootGrid.Children.Remove(oldContent);
            }
            pageContent = newContent;
            if (newContent != null)
            {
                RootGrid.Children.Add(newContent);
                // The page content is row 1 in our grid. (See diagram above.)
                Grid.SetRow((FrameworkElement)pageContent, 1);
            }
            return oldContent;
        }

        #region Data binding
        public event PropertyChangedEventHandler PropertyChanged;

        public Thickness CoreTitleBarPadding
        {
            get
            {
                // The SystemOverlayLeftInset and SystemOverlayRightInset values are
                // in terms of physical left and right. Therefore, we need to flip
                // then when our flow direction is RTL.
                if (FlowDirection == FlowDirection.LeftToRight)
                {
                    return new Thickness() { Left = coreTitleBar.SystemOverlayLeftInset, Right = coreTitleBar.SystemOverlayRightInset };
                }
                else
                {
                    return new Thickness() { Left = coreTitleBar.SystemOverlayRightInset, Right = coreTitleBar.SystemOverlayLeftInset };
                }
            }
        }

        public double CoreTitleBarHeight
        {
            get
            {
                return coreTitleBar.Height;
            }
        }
        #endregion

        public void EnableControlsInTitleBar(bool enable)
        {
            if (enable)
            {
                Window.Current.SetTitleBar(BackgroundElement);
            }
            else
            {
                Window.Current.SetTitleBar(null);
            }
        }
    }
自定义的TitleBar准备好了后,就可以在需要的时候添加或移除这个CustomTitleBar就可以了,使用前需要修改CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;  

首先需要声明:

CustomTitleBar customTitleBar = null;
需要的时候Add:

public void AddCustomTitleBar()
        {
            CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;

            if (customTitleBar == null)
            {
                customTitleBar = new CustomTitleBar();
               // customTitleBar.EnableControlsInTitleBar(true);

                // Make the main page's content a child of the title bar,
                // and make the title bar the new page content.
                UIElement mainContent = this.Content;
                this.Content = null;
                customTitleBar.SetPageContent(mainContent);
                this.Content = customTitleBar;
            }
        }
不需要的时候Remove:

  public void RemoveCustomTitleBar()
        {
            CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = false;
            if (customTitleBar != null)
            {
                // Take the title bar's page content and make it
                // the window content.
                this.Content = customTitleBar.SetPageContent(null);
                customTitleBar = null;
            }
        }
大功告成!

官方示例在此:https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/TitleBar/cs

注意:在Mobie上,应用是没有TitleBar的说法的,同时也是全屏的,因此不存在以上操作

说明一下,上述代码出自官方Demo,注释给的挺清楚,真的可以学到很多

关于自定义TitleBar,stackoverflow上有人提问如何在窗口右上方的三个键旁放一个全屏键(链接:stackoverflow),微博上的@JustinAndDesign 在回答中给出了解决方案,在这里暂不做讲解


应用窗体

到此,TitleBar的基本知识讲解差不多了。

接着说说应用窗体,其实所涉及到的东西前面已经出现过了,主要通过下面的方法获取到当前应用窗体:

var view = ApplicationView.GetForCurrentView();

view有几个主要的属性和方法:

Title:窗体的标题,区别于应用标题栏的标题

TitleBar:当前窗体对应的应用标题栏

Orientation:获取当前窗体的方向,值为Landscape或Portrait

IsFullScreen:布尔值,获取当前窗体是否是最大化

IsFullScreenMode:布尔值,获取当前窗体是否是满屏

IsOnLockScreen:布尔值,获取当前窗体是否位于Windows锁定屏幕上

IsScreenCaptureEnabled:获取或设置窗体是否启用窗体捕获

ExitFullScreenMode():方法,无返回值。退出全屏模式

TryEnterFullScreenMode():方法,返回值布尔值,进入全屏模式是否成功


Demo:切换窗体满屏显示

  private void ToggleFullScreenMode(object sender, RoutedEventArgs e)
        {
            var view = ApplicationView.GetForCurrentView();
            view.Title = "我是窗体标题";
            if (view.IsFullScreenMode)  
            {
                //退出满屏模式
                view.ExitFullScreenMode();
            }
            else
            {
                if (view.TryEnterFullScreenMode())
                {
                    //进入满屏模式成功
                }
                else
                {
                    //进入全屏模式失败
                }
            }
        }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现自定义标题栏可以通过使用QML中的Rectangle等组件来实现,并在其中添加需要的控件,例如按钮、标签、图标等。同时,为了实现与原生窗体相似的功能,可以使用QML中的Window组件,并将其属性设置为透明,然后在自定义标题栏中添加控件时,将它们放置在Window组件的边缘位置,以达到与原生窗体相似的效果。此外,还可以通过使用QML中的MouseArea组件来实现拖拽窗口的功能。具体实现方法可以参考以下示例代码: ``` import QtQuick 2.15 import QtQuick.Window 2.15 Window { visible: true width: 640 height: 480 title: "" Rectangle { id: titleBar width: parent.width height: 30 color: "#2d2d2d" MouseArea { anchors.fill: parent drag.target: parent } Label { text: "Custom Title Bar" font.bold: true color: "#ffffff" anchors.centerIn: parent } Button { text: "X" font.bold: true color: "#ffffff" anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter onClicked: { Qt.quit(); } } } Rectangle { id: content anchors.top: titleBar.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom color: "#ffffff" } } ``` 在这个示例中,我们使用了一个Rectangle组件作为自定义标题栏,并在其中添加了一个Label和一个Button。为了实现拖拽窗口的功能,我们在自定义标题栏上添加了一个MouseArea组件,并将drag.target设置为父组件。另外,我们还使用了另一个Rectangle组件作为窗口的内容区域,并通过anchors属性将其与自定义标题栏对齐。最后,我们将Windowtitle属性设置为空字符串,以隐藏原生窗口的标题栏

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值