2009-02-12 34 views
12

Ứng dụng của tôi (C#, .NET 3.5) tạo tệp và, ngoài việc tăng sự kiện có thể bị bắt và phản hồi, tôi muốn hiển thị thư mục đích cho người dùng Dưới một hình thức. Danh sách tệp đang được hiển thị trong cùng một biểu mẫu như thông tin khác.Nhúng một cá thể File Explorer trong một mẫu ứng dụng Windows Forms

Tôi đang sử dụng một thể hiện của điều khiển WebBrowser (System.Windows.Forms.WebBrowser), sau đó điều hướng đến thư mục. Điều này cho thấy một số xem mặc định của cửa sổ thám hiểm, với bảng tóm tắt tập tin bên trái và các tập tin trong khung nhìn 'Gạch' (biểu tượng lớn và văn bản).

Ví dụ,

wb.Navigate(@"c:\path\to\folder\"); 

tôi muốn ngăn chặn các bảng điều khiển và để xem danh sách tập tin trong xem chi tiết. Người dùng có thể truy cập thông qua trình đơn ngữ cảnh, nhấp chuột phải, nhưng tôi muốn nó tự động xuất hiện.

Tôi không muốn xây dựng TreeView, DataGridView hoặc bất kỳ thứ gì của riêng mình; điều khiển WebBrowser thực hiện tất cả việc cập nhật và sắp xếp lại và không có gì 'miễn phí'.

Có cách nào tốt hơn không? Một điều khiển khác để sử dụng hoặc một số đối số bổ sung để vượt qua kiểm soát?

Và nếu tôi có thể bẫy các sự kiện (ví dụ: các tệp đang được chọn/đổi tên/nhấp đúp, v.v.) thì tất cả sẽ tốt hơn!

+0

Những gì tôi thấy hữu ích là (thương mại) [thành phần ShellBrowser] (http://www.jam-software.com/shellbrowser_net/?language=EN). –

Trả lời

4

Để xử lý đổi tên, xóa và thực hiện các tùy chỉnh khác bạn cần phải viết trình khám phá tệp của riêng bạn. WebBrowser kiểm soát không phù hợp với nhu cầu của bạn. Nó chỉ là một wrapper trên thành phần ActiveX.
Bạn nên kiểm tra this codeproject article. Nó chứa một thực hiện của trình thám hiểm tập tin. Có vài mẫu hơn của trình duyệt file:
one
two

+0

Đó là điều tôi lo lắng - cần thêm nhiều mã của riêng tôi. Tôi hy vọng rằng trình duyệt web có thể có các đối số được thông qua để tiết kiệm xương lười biếng của tôi những nỗ lực! – Unsliced

0

Nếu bạn muốn mở một cửa sổ khác để hiển thị nội dung của thư mục đích, bạn có thể sử dụng System.Windows.Forms.OpenFileDialog hoặc SaveFileDialog hoặc kế thừa từ FileDialog và mở rộng nó.

Để cho phép người dùng chọn thư mục bạn có thể sử dụng FolderBrowserDialog, mặc dù là người dùng tôi không thích điều khiển đó.

Điều này có giúp ích hay bạn hoàn toàn phải nhúng điều khiển trong biểu mẫu của mình?

Asaf

+0

Ggg .. cách bạn sẽ tích hợp nó trong biểu mẫu của bạn? Và Unsliced ​​muốn hiển thị danh sách các tệp được tạo thay vì mở tệp hoặc chọn thư mục đích. – zihotki

+0

Tôi đã bắt đầu và kết thúc bằng cách yêu cầu nếu nó * có * ở cùng một dạng. Từ câu hỏi, nó không rõ ràng với tôi nếu nó được nhúng vào trong một biểu mẫu * bởi vì * nó được thực hiện với một WebBrowser, hoặc bởi vì các tập tin xem là cùng với cái gì khác. Không có cách nào thẳng về phía trước để nhúng một hộp thoại trong một biểu mẫu. –

+0

Nó không phải là trong cùng một hình thức như thông tin cần phải được hiển thị cùng với tiến độ và cập nhật trạng thái khác. Thật đáng ngạc nhiên khi chúng tôi mở/lưu hộp thoại tập tin/tạo thư mục, nhưng không ai có thể duyệt một cách rõ ràng ... – Unsliced

8

Chú ý: bài dài với rất nhiều mã.

Khi bạn điều hướng điều khiển trình duyệt web vào thư mục hệ thống tệp, điều khiển trình duyệt web sẽ lưu trữ cửa sổ chế độ xem trình duyệt mà lưu trữ chế độ xem danh sách trình khám phá. Trong thực tế, điều này hoàn toàn giống với tiến trình Explorer cũng như các hộp thoại tập tin và Internet Explorer. Cửa sổ trình bao này không phải là một điều khiển nên không có phương thức nào có thể được gọi trên nó hoặc các sự kiện có thể được đăng ký nhưng nó có thể nhận được các thông điệp cửa sổ và nó có thể được phân loại phụ.

Nó chỉ ra rằng một phần của câu hỏi của bạn đối phó với thiết lập chế độ xem để chi tiết tự động thực sự là khá dễ dàng. Trong sự kiện điều hướng của trình duyệt điều khiển trình duyệt web của bạn, chỉ cần tìm tay cầm đến cửa sổ xem vỏ và gửi cho nó một thông điệp WM_COMMAND với một hằng số vỏ cụ thể (SHVIEW_REPORT). Đây là một lệnh không có giấy tờ nhưng nó được hỗ trợ trên tất cả các nền tảng Windows lên đến và bao gồm Windows 2008 và gần như chắc chắn sẽ có trên Windows 7.Một số mã để thêm vào hình thức trình duyệt web của bạn chứng tỏ điều này:

private delegate int EnumChildProc(IntPtr hwnd, IntPtr lParam); 

    [DllImport("user32.dll", SetLastError = true)] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, 
     IntPtr wParam, IntPtr lParam); 

    [DllImport("user32.dll", SetLastError = true)] 
    private static extern int EnumChildWindows(IntPtr hWndParent, 
     EnumChildProc lpEnumFunc, IntPtr lParam); 

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, 
     int nMaxCount); 

    private const int WM_COMMAND = 0x0111; 
    private const int SHVIEW_REPORT = 0x702C; 
    private const string SHELLVIEW_CLASS = "SHELLDLL_DefView"; 

    private IntPtr m_ShellView; 

    void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e) 
    { 
     m_ShellView = IntPtr.Zero; 
     EnumChildWindows(webBrowser1.Handle, EnumChildren, IntPtr.Zero); 
     if (m_ShellView != IntPtr.Zero) 
     { 
      SendMessage(m_ShellView, WM_COMMAND, (IntPtr)SHVIEW_REPORT, (IntPtr)0); 
     } 
    } 

    private int EnumChildren(IntPtr hwnd, IntPtr lParam) 
    { 
     int retval = 1; 

     StringBuilder sb = new StringBuilder(SHELLVIEW_CLASS.Length + 1); 
     int numChars = GetClassName(hwnd, sb, sb.Capacity); 
     if (numChars == SHELLVIEW_CLASS.Length) 
     { 
      if (sb.ToString(0, numChars) == SHELLVIEW_CLASS) 
      { 
       m_ShellView = hwnd; 
       retval = 0; 
      } 
     } 

     return retval; 
    } 

Mỗi lần trình duyệt web điều hướng tới một cửa sổ mới (kể cả khi một thư mục được mở từ bên trong xem thám hiểm) một cửa sổ xem vỏ mới được tạo nên thư phải được gửi lại đến cửa sổ mới trong mọi sự kiện được điều hướng.

Đối với phần thứ hai của câu hỏi bạn muốn nhận sự kiện từ chế độ xem danh sách người khám phá. Điều này hơi khó hơn một chút so với phần đầu tiên. Để làm điều này, bạn sẽ cần phải sub-class cửa sổ xem danh sách và sau đó theo dõi các cửa sổ tin nhắn cho những người mà bạn quan tâm (chẳng hạn như WM_LBUTTONDBLCLK). Để sub-class một cửa sổ, bạn sẽ cần phải tạo lớp của riêng bạn bắt nguồn từ lớp NativeWindow và gán nó cho handle của cửa sổ mà bạn cần theo dõi. Sau đó, bạn có thể ghi đè lên quy trình Cửa sổ của nó và xử lý các thông báo khác nhau như bạn muốn. Dưới đây là một ví dụ về việc tạo một sự kiện nhấp đúp - nó tương đối đơn giản nhưng để có được quyền truy cập rộng rãi vào chế độ xem danh sách nhà thám hiểm có thể liên quan đến nhiều công việc hơn bạn sẵn sàng làm.

Thêm vào form của bạn:

private ExplorerListView m_Explorer; 

    void OnExplorerItemExecuted(object sender, ExecuteEventArgs e) 
    { 
     string msg = string.Format("Item to be executed: {0}{0}{1}", 
      Environment.NewLine, e.SelectedItem); 
     e.Cancel = (MessageBox.Show(msg, "", MessageBoxButtons.OKCancel) 
      == DialogResult.Cancel); 
    } 

và hai dòng này để xử lý lèo lái sự kiện (ngay sau khi SendMessage):

m_Explorer = new ExplorerListView(m_ShellView); 
    m_Explorer.ItemExecuted += OnExplorerItemExecuted; 

Sau đó, thêm các lớp học sau:

class ExplorerListView : NativeWindow 
{ 

    public event EventHandler<ExecuteEventArgs> ItemExecuted; 

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, 
     IntPtr wParam, IntPtr lParam); 

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    private static extern IntPtr FindWindowEx(IntPtr hwndParent, 
     IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 

    private const int WM_LBUTTONDBLCLK = 0x0203; 

    private const int LVM_GETNEXTITEM = 0x100C; 
    private const int LVM_GETITEMTEXT = 0x1073; 

    private const int LVNI_SELECTED = 0x0002; 

    private const string EXPLORER_LISTVIEW_CLASS = "SysListView32"; 

    public ExplorerListView(IntPtr shellViewHandle) 
    { 
     base.AssignHandle(FindWindowEx(shellViewHandle, IntPtr.Zero, 
      EXPLORER_LISTVIEW_CLASS, null)); 
     if (base.Handle == IntPtr.Zero) 
     { 
      throw new ArgumentException("Window supplied does not encapsulate an explorer window."); 
     } 
    } 


    protected override void WndProc(ref Message m) 
    { 
     switch (m.Msg) 
     { 
      case WM_LBUTTONDBLCLK: 
       if (OnItemExecution() != 0) return; 
       break; 
      default: 
       break; 
     } 
     base.WndProc(ref m); 
    } 

    private int OnItemExecution() 
    { 
     int cancel = 0; 
     ExecuteEventArgs args = new ExecuteEventArgs(GetSelectedItem()); 
     EventHandler<ExecuteEventArgs> temp = ItemExecuted; 
     if (temp != null) 
     { 
      temp(this, args); 
      if (args.Cancel) cancel = 1; 
     } 
     return cancel; 
    } 

    private string GetSelectedItem() 
    { 
     string item = null; 

     IntPtr pStringBuffer = Marshal.AllocHGlobal(2048); 
     IntPtr pItemBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LVITEM))); 

     int selectedItemIndex = SendMessage(base.Handle, LVM_GETNEXTITEM, (IntPtr)(-1), (IntPtr)LVNI_SELECTED).ToInt32(); 
     if (selectedItemIndex > -1) 
     { 
      LVITEM lvi = new LVITEM(); 
      lvi.cchTextMax = 1024; 
      lvi.pszText = pStringBuffer; 
      Marshal.StructureToPtr(lvi, pItemBuffer, false); 
      int numChars = SendMessage(base.Handle, LVM_GETITEMTEXT, (IntPtr)selectedItemIndex, pItemBuffer).ToInt32(); 
      if (numChars > 0) 
      { 
       item = Marshal.PtrToStringUni(lvi.pszText, numChars); 
      } 
     } 

     Marshal.FreeHGlobal(pStringBuffer); 
     Marshal.FreeHGlobal(pItemBuffer); 

     return item; 
    } 

    struct LVITEM 
    { 
     public int mask; 
     public int iItem; 
     public int iSubItem; 
     public int state; 
     public int stateMask; 
     public IntPtr pszText; 
     public int cchTextMax; 
     public int iImage; 
     public IntPtr lParam; 
     public int iIndent; 
     public int iGroupId; 
     int cColumns; // tile view columns 
     public IntPtr puColumns; 
     public IntPtr piColFmt; 
     public int iGroup; 

    } 
} 

public class ExecuteEventArgs : EventArgs 
{ 
    public string SelectedItem { get; private set; } 
    public bool Cancel { get; set; } 

    internal ExecuteEventArgs(string selectedItem) 
    { 
     SelectedItem = selectedItem; 
    } 
} 

Điều này sẽ cung cấp cho bạn ý tưởng về những gì bạn cần làm. Nếu bạn muốn nhiều hơn các sự kiện khá đơn giản, bạn có thể muốn tìm một điều khiển thay thế, mặc dù từ những gì tôi thấy trong các lĩnh vực miễn phí và chi phí thấp, có một số điều khiển khá phong nha nhưng tất cả đều có một số kỳ quặc và sẽ không cung cấp cho nhà thám hiểm liền mạch kinh nghiệm.

Hãy nhớ mã này được đặt cùng nhau một cách nhanh chóng mà không cần xử lý lỗi hoặc nhận xét và bỏ qua một số vấn đề như nhiều mục đã chọn, vì vậy hãy sử dụng nó làm phương châm và có nguy cơ của riêng bạn.

+0

Kudo cho nỗ lực trả lời, nhưng câu trả lời được chấp nhận nên đi đến giải pháp tôi thực sự đã sử dụng. Vì vậy, nếu tôi có thể chia tiền thưởng tôi đã làm, nhưng tôi thực sự đang sử dụng dự án được trích dẫn trong câu trả lời khác ... – Unsliced

+0

Nếu nó hoạt động tốt cho bạn. Mặc dù, nếu điều này không dành cho mục đích sử dụng cá nhân, tôi khuyên bạn nên sử dụng giải pháp LogicNP do uzbones đề xuất. Mục dự án mã là một nỗ lực dũng cảm nhưng nó còn mạnh mẽ để nói ít nhất. –

3

LogicNP Phần mềm có hai điều khiển (FileView và ShComboBox) mà làm những gì bạn đang tìm kiếm: http://www.ssware.com/fldrview.htm

Bạn có thể tải về dùng thử từ trang của họ, tuy nhiên nó là ~ 130 $ cho giấy phép.

1

Nếu bạn hài lòng là Windows   Chỉ có Vista và gói một điều khiển COM, IExplorerBrowser có thể được chấp nhận cho nhu cầu của bạn.

This The Code Project article cho biết việc sử dụng nó trong một chương trình MFC nhưng at least one other person dường như đã khiến nó hoạt động trong C# sau một số nỗ lực.

API mới hơn cho thấy khả năng lập trình nhiều hơn đáng kể so với việc chỉ chặn thư, nhưng rõ ràng là vô dụng đối với các nền tảng cũ hơn.

1

Kiểm tra bài viết này here, nó cho thấy cách thực hiện điều này trong .NET và WinForms. Làm theo cách này cho phép toàn quyền kiểm soát những gì người dùng nhìn thấy.

Tôi đã sử dụng nó trong một trong các ứng dụng của tôi và nó hoạt động thực sự tốt. Bạn có thể hiển thị biểu tượng/chi tiết/danh sách xem và nó dừng người dùng di chuyển đến các thư mục khác (thường là vấn đề hiển thị các hộp thoại tập tin/thư mục chuẩn.

tôi sử dụng nó để hiển thị màn hình như hình dưới đây below http://img7.imageshack.us/img7/7647/screenshotbaf.png:

3

Tôi đã viết một thư viện mà có thể có thể giúp bạn. Bạn có thể tìm thấy nó tại: http://gong-shell.sourceforge.net/

Điều khiển bạn đang tìm kiếm là ShellView. Có hướng dẫn ở đó về cách tạo một bản sao Windows Explorer đơn giản chỉ trong một vài dòng.

Lưu ý đối với người dùng .NET 4.0: Công cụ vỏ hiện bị hỏng cho 4.0. Khuôn khổ giới thiệu những thay đổi trong Interop và nó sẽ xây dựng tốt nhưng gây ra các vấn đề khác nhau khi giao tiếp với shell32 (đặc biệt là api shellicon, dẫn đến một dereference không được quản lý null).

+0

Tôi đã sử dụng điều này và tôi đã có một số vấn đề. Vấn đề lớn nhất là tôi không thể nhấp đúp chuột vào một tập tin và có nó bắt đầu ứng dụng mặc định cho tập tin. Nếu tôi cố gắng đổi tên một tệp, phím xóa sẽ không hoạt động để xóa các ký tự của tên tệp hiện có. Tôi phải sử dụng backspace. Nếu tôi gõ chữ 'i' trong khi đổi tên, các thao tác đổi tên sẽ chấm dứt! Tôi đã không dành nhiều thời gian gỡ lỗi, nhưng chúng là những vấn đề rất bực bội. –

Các vấn đề liên quan