2015-06-24 3 views
8

Używam tego przykładu, aby dostosować dialogowym ZapiszDostosuj dialogowe Zapisz plik jest podobny do bazowego OS oszczędzania dialogowym C#

http://www.codeproject.com/Articles/19566/Extend-OpenFileDialog-and-SaveFileDialog-the-easy

Działa to dobrze i mogę dostosować okna też. Jednak widzę, że niestandardowe okno dialogowe nie jest zgodne z podstawowym stylem okna. Na przykład, jeśli jestem w Windows 7 okno będzie wyglądać tak,

enter image description here

Jest to dialog zaoszczędzić od słowa i to ma kilka opcji, takich jak znaczniki i rzeczy. Ale wygląd i zachowanie są takie same, jak okno dialogowe zapisu OS. Jednak zwyczaj Zapisz dialog z powyższego linku będzie wyglądać tak,

enter image description here

Dlaczego nie obserwuj to co inne OS? Czy istnieje sposób, aby sobie z tym poradzić?


Ok, badałem trochę i dostał się do punktu, gdzie mogę wykorzystać CommonSaveFileDialog z Microsoft.WindowsAPICodePack.Dialogs i stworzyć leżącą u podstaw Zapisz okno (co robi mecz z Windows 7 stylu.). Po zainstalowaniu pakietu powłoki WindowsAPI i używane kontrolę CommonSaveFileDialog stworzyć coś takiego,

enter image description here

Kontrole oznaczone na czerwono są rzeczywiście CommonFileDialogLabel/CommonFileDialogTextBox/CommonFileDialogComboBox itp, które są przewidziane w tych API. Ale teraz moje pytanie brzmi: jak dodać do tego kontrolę użytkownika/kontrolę niestandardową? Potrzebuję pełnej kontroli nad tym, co dodaję, więc może to być kontrola użytkownika. Jakikolwiek pomysł .. Pomóżcie dzięki.

+0

To jest wspólny styl okna dialogowego systemu Windows XP. Jeśli chcesz użyć nowego Visma/7/etc. następnie należy użyć nowego wspólnego okna dialogowego elementu https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913(v=vs.85).aspx#customizing. Zobacz także ten artykuł: http://www.codeproject.com/Articles/16678/Vista-Goodies-in-C-Using-the-New-Vista-File-Dialog. –

+0

Tak to wygląda. Został zmieniony po vista. Ale podany link ma kod C++/VC++ i szukam C# .net czy jest jakiś inny link? Dzięki! – user1821499

+0

Czy ktoś może pomóc? Próbowałem dostać się do IFileDialogCustomize przykład C#, ale nie jestem w stanie użyć żadnego z nich. Przykład lub przykład byłby naprawdę pomocny! – user1821499

Odpowiedz

6

Proponowane rozwiązanie działa zgodnie z opisem:

oknie dialogowym Zapisz jako plik (stosowanego w tym przykładzie) jest związany z kontroli użytkownika, zwanego CustomSaveFileDialog. Ma tę zaletę, że jest obecny w Toolbox i automatycznie implementuje interfejs IDisposable. Jednak mogłaby to być również prosta klasa C#.

Ta kontrolka ma konstruktor akceptujący dowolną aplikację Kontrolę użytkownika zawierającą wszystkie elementy, które mają się pojawić w oknie dialogowym Plik. Kiedy mam pytanie w prawo, to właśnie jest wymagane.

CustomSaveFileDialog ma następujące właściwości:

  • Przyjmowanie arbitralnych Kontrola użytkownika zadokowany w dolnej części pliku Dialog, czyli idą zmiany rozmiaru File Dialog
  • Brak szczególnych zachowanie dodatkowych elementów (przyciski, obrazy, pola wyboru pola wyboru itp.) jest konieczne. Działają one normalnie, tak jak w innych oknach .

Jest to kod opisanego klasy:

using System; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 

namespace customSaveFileDialog 
{ 
    public partial class CustomSaveFileDialog : UserControl 
    { 
     //https://stackoverflow.com/questions/9665579/setting-up-hook-on-windows-messages 
     delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, 
      IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); 

     const uint WINEVENT_OUTOFCONTEXT = 0; 

     [DllImport("user32.dll")] 
     private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr 
      hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, 
      uint idThread, uint dwFlags); 

     [DllImport("user32.dll")] 
     private static extern bool UnhookWinEvent(IntPtr hWinEventHook); 

     [DllImport("user32.dll")] 
     private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint); 
     private struct RECT { public int Left; public int Top; public int Right; public int Bottom; } 

     [DllImport("user32.dll")] 
     private static extern bool GetClientRect(IntPtr hWnd, out RECT rc); 

     [DllImport("kernel32.dll")] 
     private static extern uint GetLastError(); 

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

     [DllImport("user32.dll", SetLastError = true)] 
     private static extern IntPtr SetParent(IntPtr hwndChild, IntPtr hwndNewParent); 

     [DllImport("user32.dll", SetLastError = true)] 
     private static extern IntPtr GetParent(IntPtr hWnd); 

     private IntPtr hDlg;  // Save As dialog handle 
     private IntPtr hHook;  // Event hook 
     private IntPtr hCtrl;  // App. specific user control handle 

     UserControl ctrl;   // App. specific user control 

     //Static variable containing the instance object 
     private static CustomSaveFileDialog customSaveFileDialog; 

     //public property for the user 
     //theSaveFileDialog has been added to the control in the designer from the Toolbox 
     public SaveFileDialog Dlg { get { return theSaveFileDialog; } } 

     //Event hook delegate 
     private static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc); 

     /// <summary> 
     /// Constructor 
     /// </summary> 
     /// <param name="ctrl">The User Control to be displayed in the file dialog</param> 
     public CustomSaveFileDialog(UserControl ctrl) 
     { 
      InitializeComponent(); 

      customSaveFileDialog = this; 
      this.ctrl = ctrl; 
      hCtrl = ctrl.Handle; 

      //Setup Hook; for simplicity, hook all possible events from the current process 
      hHook = SetWinEventHook(1, 0x7fffffff, IntPtr.Zero, 
        procDelegate, (uint)Process.GetCurrentProcess().Id, 0, WINEVENT_OUTOFCONTEXT); 
     } 


     // Hook function 
     static void WinEventProc(IntPtr hWinEventHook, uint eventType, 
      IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) 
     { 
      CustomSaveFileDialog csfdg = customSaveFileDialog; 
      if (csfdg.hDlg == IntPtr.Zero) 
       csfdg.hDlg = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "#32770", "Save As"); 

      if (hwnd == csfdg.hDlg) 
      { 
       IntPtr hParent = GetParent(csfdg.hCtrl); 

       //this is done only once 
       if (!(hParent == csfdg.hDlg)) 
        SetParent(csfdg.hCtrl, csfdg.hDlg); //Bind the user control to the Common Dialog 

       RECT cliRect; 
       GetClientRect(csfdg.hDlg, out cliRect); 

       //Position the button in the file dialog 
       MoveWindow(csfdg.hCtrl, cliRect.Left + 130, cliRect.Bottom - 55, 500, 60, true); 
      } 
     } 
    } 
} 

Zasadniczą częścią jest zahaczenie o wydarzeniach okien. Zostało to zaczerpnięte z that post.

Można zauważyć, że funkcja "FindWindowEx" (w WinEventProc) znajduje wszystkie wspólne okna dialogowe (i prawdopodobnie więcej) z tytułem "Zapisz jako". Jeśli to powinno być problemem, konieczne będzie więcej filtrowania, np. Poprzez wyszukiwanie w bieżącym wątku. Taką funkcję wyszukiwania można znaleźć here.

Dodatkowo (nie pokazano w powyższym kodzie) metoda "Usuń" w pliku CustormSaveFileDialog.desinger.cs zawiera funkcję Odłączone z uchwytem hHook jako parametrem.

Oprogramowanie zostało przetestowane w systemie Windows7 w trybie debugowania. Jako test, okno prostych form z przyciskiem został wdrożony:

 //Test for the customized "Save As" dialog 
     private void button1_Click(object sender, EventArgs e) 
     { 
      //Arbitrary User Control 
      myUserControl ctrl = new myUserControl(); 

      using (CustomSaveFileDialog csfdg = new CustomSaveFileDialog(ctrl)) 
      { 
       csfdg.Dlg.FileName = "test"; 

       //Show the Save As dialog associated to the CustomFileDialog control 
       DialogResult res = csfdg.Dlg.ShowDialog(); 
       if (res == System.Windows.Forms.DialogResult.OK) 
        MessageBox.Show("Save Dialog Finished"); 
      } 
     } 

I - jak test - kontrola applicatioin określony użytkownik obsługuje następujące zdarzenia:

using System; 
using System.Windows.Forms; 

namespace CustomFile 
{ 
    public partial class myUserControl : UserControl 
    { 
     public myUserControl() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      MessageBox.Show("Button Clicked"); 
     } 

     private void pictureBox1_Click(object sender, EventArgs e) 
     { 
      MessageBox.Show("Image Clicked"); 

     } 

     private void checkBox1_CheckedChanged(object sender, EventArgs e) 
     { 
      if (!checkBox1.Checked) 
       pictureBox1.Visible = false; 
      else 
       pictureBox1.Visible = true; 
     } 
    } 
} 

następujący wynik jest produkowany:

enter image description here

kolejne zdjęcie przedstawia inny zrzut ekranu, File Dialog zmieniany, a pole do wyświetlania obrazu jest odznaczone.

enter image description here

+0

Działa to, ale kontrola użytkownika nie może być większa niż to, co pokazano tutaj na rysunku. Pomiędzy linią "Zapisz jako typ" i "Przeglądaj/ukryj foldery" jest bardzo mało miejsca. Moja kontrola użytkownika może być większa i potrzebuję dodatkowej przestrzeni pomiędzy. czy to możliwe? – user1821499

+0

Tak, masz rację. Przedstawione rozwiązanie działa tylko dla drobnych dodatków do wspólnego okna dialogowego w przestrzeni obecnej. Możesz skonsultować się z http://www.codeproject.com/Articles/16276/Customizing-OpenFileDialog-in-NET, będąc podstawą rozwiązania cytowanego przez Ciebie w swoim stanowisku inicjującym i będąc o wiele bardziej złożonym rozwiązaniem niż przedstawione tutaj . W skrócie, IMO to śmieszne przez MS, że musimy majstrować przy wszelkiego rodzaju pinvoke, aby dostosować takie okno dialogowe. – josh

+0

Dobrze powiedziane ... Dzięki Josh. Zobaczę, jakie jest najlepsze rozwiązanie dla moich potrzeb. – user1821499

Powiązane problemy