細談c#添加搜索框和對話框

   軟件添加搜索框,實際上就是在邊框中加入一些元素,通常是用於應用程序插件程序。特別是在瀏覽器(Crome,IE,Firefox,Opera)中的右方搜索框的應用。 javascript

   通常用c#中wpf就能夠實現,前提安裝visual studio,實現效果: html


圖一:實現以前的效果                                                                                                                                         java

圖二:實現以後的效果 node

這樣的效果依賴於操做系統Aero風格的支持,也就是說在Windows Vista,Windows 7 或者更高版本中能夠得到此中效果。若是要在Windows XP中實現,那麼您就須要另外想辦法了。 web

好了。咱們來看看是怎麼實現的吧。 算法

首先:在MainWindow窗體的xaml代碼中加入如下代碼,這一步沒有什麼特別的,和日常作的同樣。 編程

 <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal"  HorizontalAlignment="Right" VerticalAlignment="Center">
 
            <TextBox Width="150"  VerticalAlignment="Center" Text="輸入關鍵詞" /> 
            <Button Content="查找" VerticalAlignment="Center" Margin="5,0,5,0" />
        </StackPanel>
 
        <Grid Background="White" Grid.Row="1">
            <Label Content="Hello World"></Label>
        </Grid>

而後:爲窗體設定背景。這一步比較重要,要實現上面圖片的效果,須要將其設定爲Transparent c#

Background="Transparent"

好了,到此xaml的編輯已經結束了,接下來看看後臺代碼是如何實現的。 windows

若是你建立的是WPF的應用程序,只須要添加System.Drawing引用便可。 api

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Interop;
using System.Runtime.InteropServices;

要實現上述效果,須要使用一個Win32函數DwmExtendFrameIntoClientArea這個函數須要個MARGINS的結構體。代碼click以下

[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
  public int cxLeftWidth;
  public int cxRightWidth;
  public int cxTopHeight;
  public int cxBottomHeight;
}

[DllImport("dwmapi.dll")]
public static extern int DwmExtendFrameIntoClientArea(
  IntPtr hWnd, ref MARGINS pMarInset);

Windows
API使用句柄控制着窗體,因此在窗體的Load事件中,第一步咱們須要獲取窗體的句柄,使用.NET類庫提供的WindowInteropHelper類來獲取。
而後從句柄中得到HwndSource,它用來宿主WPF的內容。接下來建立MARGINS結構體實例用來存儲相關設置。最後調用API。看看代碼實現:

void OnLoaded(object sender, RoutedEventArgs e)
        {
            IntPtr windowHandle = new WindowInteropHelper(this).Handle; 
            HwndSource window = HwndSource.FromHwnd(windowHandle); 
            window.CompositionTarget.BackgroundColor = Colors.Transparent; 
            MARGINS margins = new MARGINS();
            margins.cxTopHeight = 30; 
            margins = AdjustForDPISettings(margins, windowHandle); 
            int result = DwmExtendFrameIntoClientArea(windowHandle, ref margins);
        }
private MARGINS AdjustForDPISettings(MARGINS input, IntPtr hWnd)
        {
            MARGINS adjusted = new MARGINS();              
            var graphics = System.Drawing.Graphics.FromHwnd(hWnd);
            float dpiRatioX = graphics.DpiX / 96;
            float dpiRatioY = graphics.DpiY / 96;
            adjusted.cxLeftWidth = (int)(input.cxLeftWidth * dpiRatioX);
            adjusted.cxRightWidth = (int)(input.cxRightWidth * dpiRatioX);
            adjusted.cxTopHeight = (int)(input.cxTopHeight * dpiRatioY);
            adjusted.cxBottomHeight = (int)(input.cxBottomHeight * dpiRatioY);
            return adjusted;
        }

到此,整個效果就都實現了。完整代碼以下:

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace WpfTutorial
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
        }
        void OnLoaded(object sender, RoutedEventArgs e)
        {
            IntPtr windowHandle = new WindowInteropHelper(this).Handle; 
            HwndSource window = HwndSource.FromHwnd(windowHandle); 
            window.CompositionTarget.BackgroundColor = Colors.Transparent; 
            MARGINS margins = new MARGINS();
            margins.cxTopHeight = 30; 
            margins = AdjustForDPISettings(margins, windowHandle); 
            int result = DwmExtendFrameIntoClientArea(windowHandle, ref margins);
        }

        private MARGINS AdjustForDPISettings(MARGINS input, IntPtr hWnd)
        {
            MARGINS adjusted = new MARGINS();              
            var graphics = System.Drawing.Graphics.FromHwnd(hWnd);
            float dpiRatioX = graphics.DpiX / 96;
            float dpiRatioY = graphics.DpiY / 96;
            adjusted.cxLeftWidth = (int)(input.cxLeftWidth * dpiRatioX);
            adjusted.cxRightWidth = (int)(input.cxRightWidth * dpiRatioX);
            adjusted.cxTopHeight = (int)(input.cxTopHeight * dpiRatioY);
            adjusted.cxBottomHeight = (int)(input.cxBottomHeight * dpiRatioY);
            return adjusted;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MARGINS
        {
            public int cxLeftWidth;
            public int cxRightWidth;
            public int cxTopHeight;
            public int cxBottomHeight;
        }

        [DllImport("dwmapi.dll")]
        public static extern int DwmExtendFrameIntoClientArea(
          IntPtr hWnd, ref MARGINS pMarInset);
    }
}

搜索框定義好啦。

觸類旁通,使用c#定義百度搜索框,不用再進入百度網址搜索,太麻煩。

敲擊代碼以下:

using System; 
using System.Web; 
using System.Diagnostics; 
 
namespace QhCSharp{ 
    class Program{ 
        public static void Main(string[] args){ 
            if( args.Length == 0 ){ 
                Process.Start(""); 
            }else if( args.Length == 1 ){ 
                Process.Start("?wd=" + args[0]); 
            }else if( args.Length == 2 ){ 
                string searchType = args[0].ToLower(); 
                if( searchType == "news" ){ 
                    Process.Start("?word=" + HttpUtility.UrlEncode(args[1],System.Text.Encoding.GetEncoding("GB2312"))); 
                }else if( searchType == "web" ){ 
                    Process.Start("?wd=" + HttpUtility.UrlEncode(args[1],System.Text.Encoding.GetEncoding("GB2312"))); 
                }else if( searchType == "mp3" ){ 
                    Process.Start("?word=" + HttpUtility.UrlEncode(args[1],System.Text.Encoding.GetEncoding("GB2312"))); 
                }else if( searchType == "image" ){ 
                    Process.Start("?word=" + HttpUtility.UrlEncode(args[1],System.Text.Encoding.GetEncoding("GB2312"))); 
                }else if( searchType == "video" ){ 
                    Process.Start("?word=" + HttpUtility.UrlEncode(args[1],System.Text.Encoding.GetEncoding("GB2312"))); 
                }else if( searchType == "wenku" ){ 
                    Process.Start("?word=" + HttpUtility.UrlEncode(args[1],System.Text.Encoding.GetEncoding("GB2312"))); 
                }else{ 
                    Console.WriteLine("Unknown search type."); 
                } 
            }else{ 
                Console.WriteLine("Usage: Baidu <SearchType> <Keyword>"); 
                Console.WriteLine("SearchType:"); 
                Console.WriteLine("\tnews"); 
                Console.WriteLine("\tweb"); 
                Console.WriteLine("\tmp3"); 
                Console.WriteLine("\timage"); 
                Console.WriteLine("\tvideo"); 
                Console.WriteLine("\twenku"); 
            } 
        } 
    } 

這樣百度搜索框出來啦,固然也可定義Google,Yahoo等搜索框。


接着c#定義目錄搜索框

、實現方法 

1.在VS.net下新建一個C#的工程,不妨取名爲"FolderSelect",圖示以下: 

javascript:window.open(this.src);" style="cursor:pointer;"/>

2.接下來,咱們開始界面部分的設計: 

  1. 先往主界面上添加一個按鈕控件、兩個標籤控件、兩個文本框控件(用於顯示目錄的完整路徑以及目錄的一些信息)。將按鈕控件的Text屬性設置爲"瀏覽目錄選擇對話框",將兩個標籤控件的Text屬性分別設置爲"完整路徑:"、"路徑信息:",將第二個文本框的MultiLine屬性設置爲True。最終設計所得的界面以下: 


  2. 如今咱們的主界面已經好了,接着就是完成目錄選擇對話框的設計。 

    選擇VS.net的菜單:項目'添加Windows窗體,出現以下圖形: 



    選擇默認便可,按"打開"。 

    如今開始設計目錄選擇對話框的界面: 

    往窗體上添加兩個標籤控件、兩個按鈕控件、一個文本框控件、一個圖象列表(ImageList)控件和一個目錄樹(TreeView)控件。將兩個標籤控件的的Text屬性分別設置爲"完整路徑:"、"請選擇一個文件夾:";將兩個按鈕控件的Text屬性分別設置爲"選擇"和"取消";編輯圖象列表控件:給它的Images屬性添加兩個圖標 和 分別表示文件夾關閉和打開狀態;將目錄樹控件的ImageList屬性設置爲imageList1,並將它的ImageIndex和SelectedImageIndex屬性分別設置爲0和1。好了,最終的界面以下: 








3.如今咱們開始編寫代碼: 

由於咱們的程序中均用到了有關目錄信息的類,因此必須在每一個代碼文件的頭上添加System.IO名字空間,具體以下: 

using System.IO; 

  1. 對於主窗體部分,咱們要寫的代碼量相對較少。由於這是一個測試用的程序,因此主窗體的做用只是用來顯示用戶所選擇的目錄的一些相關信息以代表程序能正常運行、目錄選擇對話框能正常工做,因此只要添加主窗體上按鈕的OnClick事件函數便可:
    private void button1_Click(object sender, System.EventArgs e) 

    try 

    Form2 dlg = new Form2(); if ( dlg.ShowDialog() == DialogResult.OK) 

    DirectoryInfo info = dlg.info; 
    textBox1.Text = dlg.fullPath; 

    // 在文本框中添加目錄信息 
    string [] strArray = new string[4]; 

    strArray[0] = "建立時間 : "+ info.CreationTime.ToString(); 
    strArray[1] = "全名 : "+ info.FullName; 
    strArray[2] = "上次訪問時間 : "+ info.LastAccessTime.ToString(); 
    strArray[3] = "上次改寫時間 : "+ info.LastWriteTime.ToString(); 

    textBox2.Lines = strArray; 


    catch( Exception err) 

    Console.WriteLine(err.Message); 

    }
  2. 對於文件選擇對話框,咱們要完成系統驅動器及其子目錄的取得並顯示、設定目錄路徑信息以及目錄相關信息等工做,因此代碼量相對較大。先給該類添加兩個必須的私有數據成員以下:
    private static string driveLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    // 用於列舉驅動器盤符 
    private DirectoryInfo folder; // 用於保存目錄信息 

    修改類的構造函數以下:fillTree()函數在後面介紹 
    public Form2() 

    // 
    // Required for Windows Form Designer support 
    // 
    InitializeComponent(); 

    // 
    // TODO: Add any constructor code after InitializeComponent call 
    // 
    fillTree();// 該函數調用完成目錄選擇對話框的初始設置 
    }


    接着爲該類添加幾個有用的成員函數fillTree()、getSubDirs()、fixPath(),訪問類型均爲Private。fillTree()函數用來設置目錄樹的各個節點以填充到目錄樹控件,這樣目錄樹中就充滿了系統中各個根目錄以及其全部子目錄的節點。getSubDirs()函數用來得到各個目錄節點可能存在的全部子節點,其中用到了遞推搜索算法。fixPath()函數用來設置文本框的內容,使當前用戶所選擇的目錄顯示在文本框中。各函數以下: 

    private void fillTree() 

    DirectoryInfo directory; 
    string sCurPath = ""; // 從新清空 
    treeView1.Nodes.Clear(); 

    // 將硬盤上的全部的驅動器都列舉出來 
    foreach( char c in driveLetters ) 

    sCurPath = c + ":\\"; 
    try 

    // 得到該路徑的目錄信息 
    directory = new DirectoryInfo(sCurPath); 

    // 若是得到的目錄信息正確,則將它添加到目錄樹視中 
    if ( directory.Exists == true ) 

    TreeNode newNode = new TreeNode(directory.FullName); 
    treeView1.Nodes.Add(newNode); // 添加新的節點到根節點 
    getSubDirs(newNode); 
    // 調用getSubDirs()函數,檢查該驅動器上的任何存在子目錄 


    catch( Exception doh) 

    Console.WriteLine(doh.Message); 




    private void getSubDirs( TreeNode parent ) 

    DirectoryInfo directory; 
    try 

    // 若是尚未檢查過這個文件夾,則檢查之 
    if ( parent.Nodes.Count == 0 ) 

    directory = new DirectoryInfo(parent.FullPath); 
    foreach( DirectoryInfo dir in directory.GetDirectories()) 

    // 新建一個數節點,並添加到目錄樹視 
    TreeNode newNode = new TreeNode(dir.Name); 
    parent.Nodes.Add(newNode); 



    foreach(TreeNode node in parent.Nodes) 

    // 若是尚未檢查過這個文件夾,則檢查 
    if (node.Nodes.Count == 0) 

    directory = new DirectoryInfo(node.FullPath); 

    // 檢查該目錄上的任何子目錄 
    foreach( DirectoryInfo dir in directory.GetDirectories()) 

    // 新建一個數節點,並添加到目錄樹視 
    TreeNode newNode = new TreeNode(dir.Name); 
    node.Nodes.Add(newNode); 




    catch( Exception doh ) 

    Console.WriteLine(doh.Message); 



    private string fixPath( TreeNode node ) 

    string sRet = ""; 
    try 

    sRet = node.FullPath; 
    int index = sRet.IndexOf("\\\\"); 
    if (index > 1 ) 

    sRet = node.FullPath.Remove(index, 1); 


    catch( Exception doh ) 

    Console.WriteLine(doh.Message); 

    return sRet; 
    }


    接着,給該類添加如下幾個屬性,這幾個屬性都是反映所選擇的目錄的相關信息的,它們將被主窗體的類調用: 

    public string name// 返回所選擇的目錄的名稱 

    get { return ((folder != null && folder.Exists))? folder.Name : null; } 
    } public string fullPath// 返回所選擇的目錄的完整路徑 

    get { return ((folder != null && folder.Exists && treeView1.SelectedNode != null))? fixPath(treeView1.SelectedNode) : null; } 


    public DirectoryInfo info// 返回所選擇的目錄的信息 

    get { return ((folder != null && folder.Exists))? folder : null; } 
    }


    最後,還要添加目錄樹控件的BeforeSelect()和BeforeExpand()事件函數以及兩個按鈕的OnClick事件函數。BeforeSelect()事件函數是用戶選定目錄前的一個事件函數,它完成了子目錄取得、設置文本框內容、獲取該目錄信息等功能。一樣,BeforeExpand()事件函數完成類似的功能,只不過它是在目錄節點被展開前發生的。具體的函數實現以下: 

    private void treeView1_BeforeSelect(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) 

    getSubDirs(e.Node); // 取得選擇節點的子文件夾 
    textBox1.Text = fixPath(e.Node); // 更新文本框內容 
    folder = new DirectoryInfo(e.Node.FullPath); // 得到它的目錄信息 


    private void treeView1_BeforeExpand(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) 

    getSubDirs(e.Node); // 取得選擇節點的子文件夾 
    textBox1.Text = fixPath(e.Node); // 更新文本框內容 
    folder = new DirectoryInfo(e.Node.FullPath); // 得到它的目錄信息 


    private void button1_Click(object sender, System.EventArgs e) 
    // "選擇"按鈕的消息處理函數 

    this.DialogResult = DialogResult.OK; 
    this.Close(); 


    private void button2_Click(object sender, System.EventArgs e) 
    // "取消"按鈕的消息處理函數 

    folder = null; 
    this.Close(); 
    }


4.到此爲止,咱們已經完成了全部的代碼編寫工做。如今能夠按Ctrl+F5試試運行效果了。首先會出現下面的主窗體: 



按下"瀏覽目錄選擇對話框"按鈕後就出現下面的目錄選擇對話框了: 



在目錄選擇對話框上選定一個目錄後,咱們按"選擇"按鈕。這樣咱們又回到了程序的主界面。由於該主界面是用來顯示所選擇的目錄的一些相關信息的,其中包括了:完整路徑、路徑信息中的建立時間、全名、上次訪問時間、上次改寫時間等。圖示以下: 



這樣,咱們就完成了程序的測試工做了。固然這樣的範例是尚未實用功能的,不過你能夠試着用一樣的方法開發出一個合適的目錄選擇對話框運用到本身的應用程序中,甚至是一個目錄選擇對話框組件以供後來者使用,讓更多的人受益於你的成果。這樣其效用就徹底不一樣了,做爲做者的我也會感到至關欣慰的。 

啓示錄 

如今這個程序雖然只具備通常的目錄選擇功能,不過作完這個程序,咱們不難發現用C#完成一些應用程序是很是方便的。相比之前咱們在SDK、MFC下完成這些還要寫不少東西,工做量是很是大並且複雜的。如今微軟爲咱們作好了許多此類工做,咱們何不樂意接受呢?

開啓c#編程之旅吧

adiOS

相關文章
相關標籤/搜索