美文网首页野生技术宅协会.NETWPF
用WPF做一个简易浏览器

用WPF做一个简易浏览器

作者: 乐百川 | 来源:发表于2017-06-30 01:00 被阅读626次

    微软的WPF(Windows Presentation Foundation)是目前Windows平台上最好用的图形界面框架了。如果想在Windows平台上编写图形界面程序,而且没有跨平台且性能需求比较高,而且对C#语言比较熟悉,那么WPF就是最适合你的了。

    WPF虽然出来也有大概十来年了,但是它的很多设计思想还是非常先进的,配合C#这门语言的话更加顺手。WPF的界面设计和程序功能完全解耦,也就是说设计界面和编写程序功能可以互不干扰的同时进行。

    好了,废话不多说,下面直接开始吧。当然需要说明,这篇文章不是讲如何实现浏览器的,而是利用WPF的一个浏览器控件,让大家了解一下WPF的一些简单功能。由于WPF组件庞大,没办法在一篇文章中详细介绍。所以如果大家通过这篇文章对WPF有了一些兴趣,那么这篇文章的目的就达到了。

    先来看看效果图吧。当然功能比较简陋,只有前进、后退、刷新几个功能。当然如果太复杂,就没办法在一篇文章中说完了。

    效果图

    界面设计

    布局

    不管是什么图形界面框架,首先讨论的都是界面布局了。布局负责组织界面元素如何排列和显示。合适的界面布局可以降低我们程序界面的复杂度。如果需要了解布局的话,可以看看这篇英文文章,或者查找其他中文文章。

    这里简单说一下常用的几种布局:

    • StackPanel。将部件按照垂直或水平顺序依次排列。
    • WrapPanel。和前者差不多,不过如果部件太多,会自动安排到下一行显示。
    • DockPanel。可以指定上下左右中五个方位的组件。
    • Grid。网格布局,可以按照网格形式排列组件。

    现在返回来看看这个浏览器的布局。首先第一行是按钮和地址栏,第二行就是浏览器控件了。所以在这里我使用了DockPanel,第一行我指定为Top;第二行不指定,也就是充满整个剩余空间。

    然后来看看第一行的布局,这里我希望前三个按钮按顺序排列,最后的地址栏充满整个剩余空间。所以第一行本身也需要使用DockPanel来实现。

    最后来看看相应的XAML代码,虽然说得比较多,但是代码倒是很少。

    <DockPanel>
        <DockPanel DockPanel.Dock="Top">
            <Button Name="ForwardButton" Content="前进" Click="ForwardButton_Click" />
            <Button Name="BackButton" Content="后退" Click="BackButton_Click" />
            <Button Name="RefreshButton" Content="刷新" Click="RefreshButton_Click" />
            <TextBox Name="UrlTextBox" KeyDown="UrlTextBox_KeyDown" />
        </DockPanel>
        <WebBrowser Name="BrowserControl" />
    </DockPanel>
    

    控件

    其实关于控件我倒是没什么说的。不管是哪种图形界面,反正控件总是按钮、文本域、标签那些东西。这里我用到的就是按钮和文本框,当然最重要的是WPF提供的浏览器控件WebBrowser,它封装了浏览器的操作以便我们直接使用。

    当然WPF还有一个非常重要的特点就是代码可以无缝引用界面控件,这一点将在后面体现。这个特点可是很多图形界面框架不提供的,比方说安卓的代码要引用界面元素的话就得使用getElementById方法。

    样式

    最后要说的就是样式了。WPF的样式和HTML的样式在语法上很相似,我们既可以直接在界面元素上指定它的样式,也可以在其他地方统一管理。当然如果要符合软件设计的最佳实践,样式当然需要在一个地方统一指定比较好。

    当然,WPF的样式非常丰富,可以对一个控件进行深度定制,让它“重新做人”。所以我就不做介绍了,等到需要的时候在查阅就行了。这里只设置了按钮和文本框的宽度和外边距,外边距的4个值分别代表上、左、右、下外边距。如果不在这里统一设置,那么就要针对每个按钮设置一次外边距,这是件很麻烦的事情。

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Width" Value="45" />
            <Setter Property="Margin" Value="10,10,0,10" />
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="Margin" Value="10,10,10,10" />
        </Style>
    </Window.Resources>
    

    功能编写

    事件处理

    说完了界面的部分,下面来说说如何编写程序功能。利用强大的XAML,我们可以非常方便的将界面组件和功能代码对应起来。C#有一个特性叫做事件,WPF也利用了事件来处理程序响应。WPF的控件都包含了大量事件,可以处理鼠标、键盘、触屏等等各种事件,而且仅需要在XAML代码中添加一点代码就可以将事件和处理程序绑定起来。下面代码中的ClickKeyDown就是两个事件,用于处理单击鼠标和键盘按键。

    <DockPanel>
        <DockPanel DockPanel.Dock="Top">
            <Button Name="ForwardButton" Content="前进" Click="ForwardButton_Click" />
            <Button Name="BackButton" Content="后退" Click="BackButton_Click" />
            <Button Name="RefreshButton" Content="刷新" Click="RefreshButton_Click" />
            <TextBox Name="UrlTextBox" KeyDown="UrlTextBox_KeyDown" />
        </DockPanel>
        <WebBrowser Name="BrowserControl" />
    </DockPanel>
    

    每个事件的处理函数签名都不相同,比方说单击鼠标的事件签名就是Click(object sender, RoutedEventArgs e),而按下键盘的事件签名是KeyDown(object sender, KeyEventArgs e)。在Visual Studio中我们只需要选择控件,然后点击属性中的相应事件,即可自动生成处理函数,我们只需要编写代码即可。

    VS截图

    浏览器控件

    说完了事件机制,下面我们来看看如何用它来搞点事情。由于WPF提供了方便的浏览器控件,所以这里的代码非常简单,只需要调用浏览器控件的相应方法即可。由于没有单独的处理按下回车的事件,所以这里用的是按下键盘的事件,然后在处理程序中判断按下的是否是回车键,如果是的话再进行下一步处理,也就是让浏览器导航到对应网址。

    private void ForwardButton_Click(object sender, RoutedEventArgs e)
    {
        BrowserControl.GoForward();
    }
    private void BackButton_Click(object sender, RoutedEventArgs e)
    {
        BrowserControl.GoBack();
    }
    private void RefreshButton_Click(object sender, RoutedEventArgs e)
    {
        BrowserControl.Refresh();
    }
    private void UrlTextBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Return)
        {
            var url = UrlTextBox.Text;
            BrowserControl.Navigate(url);
        }
    }
    

    自动补全URL

    上面的代码已经基本可以使用,不过还是有一个小问题。那就是如果输入的不是URL格式(http://www.baidu.com),而是网址(www.baidu.com),那么程序就会崩掉。因为浏览器控件只能接受URL形式的字符串,如果不是合法的URL,那么BrowserControl.Navigate(url)这一句代码就会抛出异常。

    那么这个问题该如何解决呢?我在这里直接使用正则表达式做一下测试,如果如果输入的不是有效的URL,那么我就手动在网址前面添加一个 http://。实现方法很简单,直接看代码就行了。

    public partial class MainWindow : Window
    {
        private readonly Regex _urlPattern = new Regex(@"\w*://\w*(.\w*)+");
        public MainWindow()
        {
            InitializeComponent();
        }
        //省略了那些事件处理程序
        private void UrlTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                var url = UrlTextBox.Text;
                if (!_urlPattern.IsMatch(url))
                {
                    url = "http://" + url;
                }
                BrowserControl.Navigate(url);
            }
        }
    }
    

    如果留心一下前面的XAML就会发现,在下面的代码中直接引用了XAML中浏览器控件的名字BrowserControl,并可以调用它的属性和方法。这也是浏览·WPF一个非常方便的特性。

    更改地址栏URL

    下面就剩下最后一个问题了。一般浏览器的地址栏,会随着访问网址的变化而变化。但是我们这个浏览器却没有这个功能,地址栏的地址永远是输入的那个地址。现在我们希望不论是前进、后退,还是从浏览器中点击其他链接,地址栏的地址都会跟着更新。

    当然实现这个功能也很简单,查阅一下浏览器控件就可以发现,它有一个属性叫做Source,恰好就是当前页面的URL,所以利用这个属性就可以完美的实现我们的功能了。这样,只需要一行代码UrlTextBox.Text = BrowserControl.Source.ToString();就可以搞定了。

    当然问题又来了,这行代码应该往哪里加呢?第一种办法是在所有处理程序中添加这行代码, 也就是说,前进、后退的处理程序都需要进行修改。这样并不是一个好办法,万一将来需求发生了变化,有好几处地方都要修改,更容易出错。解决办法还是刚才说的事件。经过一番查找,我发现了WebBrowserNavigated事件,顾名思义,这个事件会在调用了Navigate方法后触发。这样,只需要把这一行代码绑定到这个事件上就行了,代码非常优雅,酷毙了!

    public MainWindow()
    {
        InitializeComponent();
        BrowserControl.Navigated += BrowserControl_Navigated;
    }
    private void BrowserControl_Navigated(object sender, NavigationEventArgs e)
    {
        UrlTextBox.Text = BrowserControl.Source.ToString();
    }
    

    这样,一个简易的浏览器就实现完毕了。代码我放在了Csdn Code,有兴趣的同学可以看看。

    相关文章

      网友评论

        本文标题:用WPF做一个简易浏览器

        本文链接:https://www.haomeiwen.com/subject/cqgvcxtx.html