Как настроить OpenFileDialog для выбора папок?

212

В VS.NET, когда вы выбираете папку для проекта, отображается диалоговое окно, похожее на OpenFileDialog или SaveFileDialog, но настроено для приема только папок. С тех пор, как я это увидел, я хотел знать, как это делается. Я знаю FolderBrowserDialog, но мне никогда не нравился этот диалог. Он начинает слишком мал и не позволяет мне использовать возможность ввода пути.

Я почти уверен, что сейчас нет способа сделать это с .NET, но мне также любопытно, как вы это делаете и из неуправляемого кода. Не удалось полностью изменить диалог с нуля, как изменить диалог, чтобы иметь такое поведение?

Я также хотел бы подтвердить, что мне известно о FolderBrowserDialog, но иногда я не люблю его использовать, кроме того, что мне действительно интересно, как настроить диалог таким образом. Говорить мне просто использовать FolderBrowserDialog помогает мне поддерживать постоянный опыт пользовательского интерфейса, но не удовлетворяет мое любопытство, поэтому оно не будет считаться ответом.

Это не особая вещь для Vista; Я видел это диалоговое окно с VS.NET 2003, так что это можно сделать в Win2k и WinXP. Это меньше, чем "Я хочу знать, как правильно это сделать", и больше "Мне было интересно об этом, так как я сначала хотел сделать это в VS 2003". Я понимаю, что в диалоговом окне файла Vista есть возможность сделать это, но он работает в XP, поэтому я знаю, что они что-то сделали, чтобы заставить его работать. Ответы, специфичные для Vista, не являются ответами, потому что Vista не существует в контексте вопроса.

Обновление: я принимаю ответ Скотта Вишневского, потому что он поставляется с рабочим образцом, но я считаю, что Серж заслуживает внимания, указав на настройку диалога (что, по общему признанию, отвратительно от .NET, но оно действительно работает) и Mark Выкуп для выяснения того, что MS, вероятно, развернула специальный диалог для этой задачи.

  • 6
    просто простое решение из codeproject codeproject.com/Articles/44914/… [ключом к получению OpenFileDialog для выбора как файлов, так и папок является установка для свойств ValidateNames и CheckFileExists значения false (dialog.ValidateNames = false; dialog.CheckFileExists = false) и установите для FileName какое-то специальное ключевое слово, чтобы убедиться, что папки выбраны (dialog.FileName = "Выбор папки";).]
  • 3
    Отправить это как ответ, это сделало работу для моего проекта.
Показать ещё 3 комментария
Теги:
winapi
openfiledialog

16 ответов

52
Лучший ответ

У меня есть диалог, который я написал, называется диалогом OpenFileOrFolder, который позволяет вам открыть папку или файл.

Если вы установите для параметра AcceptFiles значение false, то он будет работать только в режиме приема файлов.

Здесь вы можете скачать источник из GitHub

  • 4
    Очень интересно и определенно так же сложно, как я рассчитывал. Есть ли возможность комментировать и указывать, что он делает? Это наряду с другими комментариями заставляет меня поверить, что MS, вероятно, просто развернула свой собственный диалог.
  • 1
    Я получаю следующую ошибку, когда пытаюсь построить ваше решение ... к сожалению, c ++ не входит в мои сильные стороны ... Ошибка 1 не может открыть включаемый файл 'afxres.h'.
Показать ещё 11 комментариев
46

Существует пакет кода Windows API. Он получил много связанных с оболочкой вещей, включая класс CommonOpenFileDialog (в пространстве имен Microsoft.WindowsAPICodePack.Dialogs). Это идеальное решение - обычный открытый диалог с отображением только папок.

Вот пример того, как его использовать:

CommonOpenFileDialog cofd = new CommonOpenFileDialog();
cofd.IsFolderPicker = true;
cofd.ShowDialog();

К сожалению, Microsoft больше не отправляет этот пакет, но несколько человек имеют неофициально загруженные двоичные файлы в NuGet. Один пример можно найти здесь. Этот пакет - это всего лишь оболочка. Если вам это нужно, у того же пользователя есть несколько других пакетов, которые предлагают больше функциональности, присутствующих в исходном пакете.

  • 1
    Я не знал, что это в Windows API Code Pack - спасибо за указание на это.
  • 10
    Класс CommonOpenFileDialog существует только в Windows Vista или более поздней версии, поэтому будет возникать исключение в старых операционных системах.
Показать ещё 8 комментариев
42

Вы можете использовать FolderBrowserDialogEx - повторно используемую производную от встроенного FolderBrowserDialog. Это позволяет вам вводить путь, даже путь UNC. Вы также можете просматривать компьютеры или принтеры с ним. Работает так же, как встроенный FBD, но... лучше.

(EDIT: я должен был указать, что этот диалог может быть установлен для выбора файлов или папок.)

Полный исходный код (один короткий С# -модуль). Свободно. Лицензия MS-Public.

Код для использования:

var dlg1 = new Ionic.Utils.FolderBrowserDialogEx();
dlg1.Description = "Select a folder to extract to:";
dlg1.ShowNewFolderButton = true;
dlg1.ShowEditBox = true;
//dlg1.NewStyle = false;
dlg1.SelectedPath = txtExtractDirectory.Text;
dlg1.ShowFullPathInEditBox = true;
dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

// Show the FolderBrowserDialog.
DialogResult result = dlg1.ShowDialog();
if (result == DialogResult.OK)
{
    txtExtractDirectory.Text = dlg1.SelectedPath;
}
  • 7
    Извините, если я обиделась, просто неприятно задавать вопрос и говорить «Я хочу эту конкретную вещь, а не эти другие вещи», и люди с радостью предлагают незапрошенную вещь. Я хотел диалог браузера файлов, а не диалог браузера папок.
  • 15
    Если сформулировать вопрос, мне кажется, что он запрашивает диалог выбора папки - разве это не так? Во всяком случае, это именно то, что я искал +1
Показать ещё 6 комментариев
31

Пакет Ookii.Dialogs содержит управляемую оболочку вокруг нового диалогового окна браузера папок в стиле Vista. Он также изящно деградирует в старых операционных системах.

  • 2
    Круто, это открытый исходный код в стиле BSD!
  • 7
    Единственная проблема в том, что я не позволю мне использовать клиентский профиль .net Framework в качестве цели.
Показать ещё 6 комментариев
30

Лучше использовать для этого FolderBrowserDialog.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}
  • 0
    +1, браузер папок Visual Studio, похожий на файловый браузер - плохая идея
  • 7
    Я знаю, что лучше использовать FolderBrowserDialog. Мне любопытно, как это было сделано независимо. В любом случае FolderBrowserDialog воняет во многих отношениях; даже в Vista нет панели мест. Забавно, как если бы это было лучше MS до сих пор избегал этого в 3 версиях VS.
Показать ещё 10 комментариев
19

После нескольких часов поиска я нашел этот ответ от leetNightShade до рабочее решение.

Есть три вещи, которые, я считаю, делают это решение намного лучше, чем все остальные.

  • Прост в использовании. Это требует, чтобы вы включили в свой проект два файла (которые могут быть объединены в один момент).
  • Возвращается к стандартному FolderBrowserDialog при использовании на XP или более старых систем.
  • Автор предоставляет разрешение на использование кода для любых целей, которые вы сочтете подходящими.

    Нет лицензии, так как вы свободны принимать и делать с кодом, что хотите.

Загрузите код здесь.

  • 0
    @MattDavis: я подтвердил, что он работает в .NET Framework 4.0 (как стандартный, так и клиентский профиль). Просто убедитесь, что у вас есть и FolderSelectDialog.cs и Reflector.cs, добавленные в ваш проект. Одна вещь, хотя ... вы работаете на Windows 8? Я тестировал на компьютере Win7.
  • 0
    @ Алекс Эссильфи, ты прав. Должно быть, я сделал что-то не так, втянув это в свой проект. Я удалю свой предыдущий комментарий для ясности.
Показать ещё 3 комментария
17

Exact Audio Copy работает именно так в Windows XP. Отображается стандартный диалог открытия файла, но в поле имени файла содержится текст "Имя файла будет проигнорировано".

Просто угадай здесь, но я подозреваю, что строка вводится в элемент управления списком со списком каждый раз, когда в диалог вносятся значительные изменения. Пока поле не пустое, а флаги диалога установлены, чтобы не проверять наличие файла, диалог может быть закрыт нормально.

Изменить: это намного проще, чем я думал. Здесь код в С++/MFC, вы можете перевести его в среду по вашему выбору.

CFileDialog dlg(true, NULL, "Filename will be ignored", OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_PATHMUSTEXIST | OFN_READONLY, NULL, this);
dlg.DoModal();

Редактировать 2: Это должен быть перевод на С#, но я не владею С#, поэтому не стреляйте в меня, если он не работает.

OpenFileDialog openFileDialog1 = new OpenFileDialog();

openFileDialog1.FileName = "Filename will be ignored";
openFileDialog1.CheckPathExists = true;
openFileDialog1.ShowReadOnly = false;
openFileDialog1.ReadOnlyChecked = true;
openFileDialog1.CheckFileExists = false;
openFileDialog1.ValidateNames = false;

if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
    // openFileDialog1.FileName should contain the folder and a dummy filename
}

Редактировать 3: Наконец, посмотрел фактический диалог в Visual Studio 2005 (раньше у меня не было доступа к нему). Это не стандартный диалог открытия файла! Если вы проверяете окна в Spy ++ и сравниваете их со стандартным открытым файлом, вы увидите, что имена структуры и класса не совпадают. Когда вы смотрите внимательно, вы также можете обнаружить некоторые различия между содержимым диалогов. Я пришел к выводу, что Microsoft полностью заменила стандартный диалог в Visual Studio, чтобы дать ему эту возможность. Мое решение или что-то подобное будет таким же близким, как вы можете получить, если только вы не захотите вводить код с нуля.

17

Хорошо, позвольте мне попытаться подключить первую точку;-) Игра немного с Spy ++ или Winspector показывает, что текстовое поле Folder в VS Project Location - это настройка стандартного диалога. Это не то же поле, что и текстовое поле filename в стандартном диалоговом окне файла, например, в "Блокноте".

Оттуда, я полагаю, VS скрывает имя файла и текстовые поля типа файла /comboboxes и использует собственный шаблон диалога, чтобы добавить свою собственную часть в нижней части диалогового окна.

EDIT: Вот пример такой настройки и того, как это сделать (в Win32, а не .NET):

m_ofn - это структура OPENFILENAME, которая лежит в основе диалогового окна файла. Добавьте эти 2 строки:

  m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEDIALOG_IMPORTXLIFF);
  m_ofn.Flags |= OFN_ENABLETEMPLATE;

где IDD_FILEDIALOG_IMPORTXLIFF - это шаблон настраиваемого диалога, который будет добавлен в нижней части диалогового окна. См. Красную часть. alt text http://apptranslator.com/_so/customizedfiledialog.png

В этом случае настраиваемая часть представляет собой только метку + гиперссылку, но это может быть любой диалог. Он может содержать кнопку "ОК", которая позволяет нам проверять выбор только для папки.

Но как мы могли бы избавиться от некоторых элементов управления в стандартной части диалога, я не знаю.

Подробнее в этой статье MSDN.

  • 1
    Это звучит как некоторые объяснения, которые я слышал в прошлом, но я никогда не видел демонстрацию концепции. Есть ли в документации MSDN прохождение по этому поводу?
10

Вы можете подклассифицировать диалог файла и получить доступ ко всем его элементам управления. Каждый из них имеет идентификатор, который можно использовать для получения дескриптора окна. Затем вы можете отображать и скрывать их, получать от них сообщения об изменениях выбора и т.д. Все зависит от того, сколько усилий вы хотите предпринять.

Мы использовали нашу поддержку класса WTL и настроили диалоговое окно файла, чтобы включить пользовательскую панель мест и плагины COM-представлений.

MSDN содержит информацию о том, как это сделать, используя Win32, эта статья CodeProject включает пример, и эта статья CodeProject предоставляет пример .NET.

9

Вы можете использовать код, подобный этому

  • Фильтр скрывает файлы
  • Имя файла скроет первый текст

Для расширенного скрытия текстового поля для имени файла вам нужно посмотреть OpenFileDialogEx

Код:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}
  • 0
    Просто и это то, что мне нужно для Windows 7+
  • 0
    Также OFN_NOVALIDATE требуется в флагах
5

Я предполагаю, что вы используете Vista, используя VS2008? В этом случае я думаю, что FOS_PICKFOLDERS опция используется при вызове диалогового окна файла Vista IFileDialog. Я боюсь, что в .NET-коде это будет связано с большим количеством gnarly кода взаимодействия P/Invoke для работы.

  • 1
    Vista, конкретные; Я впервые увидел это на VS 2003 на Windows XP.
1

Первое решение

Я разработал это как очищенную версию . В диалоговом окне выбора папки NET Win 7 в стиле Билл Сэддон из lyquidity.com (у меня нет аффилированности). (Я узнал о его коде из другого ответа на этой странице). Я написал свой собственный, потому что для его решения требуется дополнительный класс Reflection, который не нужен для этой целенаправленной цели, использует управление потоком на основе исключений, не кэширует результаты своих вызовов отражения. Обратите внимание, что вложенный статический класс VistaDialog таков, что его статические переменные отражения не пытаются заселяться, если метод Show никогда не вызывается. Он возвращается к диалогу pre-Vista, если не в достаточно высокой версии Windows. Должен работать в Windows 7, 8, 9, 10 и выше (теоретически).

using System;
using System.Reflection;
using System.Windows.Forms;

namespace ErikE.Shuriken {
    /// <summary>
    /// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions
    /// </summary>
    public class FolderSelectDialog {
        private string _initialDirectory;
        private string _title;
        private string _fileName = "";

        public string InitialDirectory {
            get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; }
            set { _initialDirectory = value; }
        }
        public string Title {
            get { return _title ?? "Select a folder"; }
            set { _title = value; }
        }
        public string FileName { get { return _fileName; } }

        public bool Show() { return Show(IntPtr.Zero); }

        /// <param name="hWndOwner">Handle of the control or window to be the parent of the file dialog</param>
        /// <returns>true if the user clicks OK</returns>
        public bool Show(IntPtr hWndOwner) {
            var result = Environment.OSVersion.Version.Major >= 6
                ? VistaDialog.Show(hWndOwner, InitialDirectory, Title)
                : ShowXpDialog(hWndOwner, InitialDirectory, Title);
            _fileName = result.FileName;
            return result.Result;
        }

        private struct ShowDialogResult {
            public bool Result { get; set; }
            public string FileName { get; set; }
        }

        private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string title) {
            var folderBrowserDialog = new FolderBrowserDialog {
                Description = title,
                SelectedPath = initialDirectory,
                ShowNewFolderButton = false
            };
            var dialogResult = new ShowDialogResult();
            if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK) {
                dialogResult.Result = true;
                dialogResult.FileName = folderBrowserDialog.SelectedPath;
            }
            return dialogResult;
        }

        private static class VistaDialog {
            private const string c_foldersFilter = "Folders|\n";

            private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
            private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
            private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
            private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
            private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
            private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
            private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
            private readonly static uint s_fosPickFoldersBitFlag = (uint) s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialogNative+FOS")
                .GetField("FOS_PICKFOLDERS")
                .GetValue(null);
            private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
                .GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null);
            private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
            private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
            private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");

            public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory, string title) {
                var openFileDialog = new OpenFileDialog {
                    AddExtension = false,
                    CheckFileExists = false,
                    DereferenceLinks = true,
                    Filter = c_foldersFilter,
                    InitialDirectory = initialDirectory,
                    Multiselect = false,
                    Title = title
                };

                var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
                s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
                s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint) s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
                var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
                s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);

                try {
                    int retVal = (int) s_showMethodInfo.Invoke(iFileDialog, new object[] { ownerHandle });
                    return new ShowDialogResult {
                        Result = retVal == 0,
                        FileName = openFileDialog.FileName
                    };
                }
                finally {
                    s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
                }
            }
        }

        // Wrap an IWin32Window around an IntPtr
        private class WindowWrapper : IWin32Window {
            private readonly IntPtr _handle;
            public WindowWrapper(IntPtr handle) { _handle = handle; }
            public IntPtr Handle { get { return _handle; } }
        }
    }
}

Он используется в форме Windows:

var dialog = new FolderSelectDialog {
    InitialDirectory = musicFolderTextBox.Text,
    Title = "Select a folder to import music from"
};
if (dialog.Show(Handle)) {
    musicFolderTextBox.Text = dialog.FileName;
}

Вы можете, конечно, поиграть со своими опциями и свойствами, которые он предоставляет. Например, он позволяет многозадачность в диалоговом окне в стиле Vista.

Второе решение

Саймон Мурри дал ответ, в котором показано, как выполнить то же самое, используя взаимодействие с Windows API напрямую, хотя его версия должна быть дополнена для использования более старый стиль, если в старой версии Windows. К сожалению, я еще не нашел его сообщение, когда решил свое решение. Назовите свой яд!

  • 0
    Подобный пример использования для вызова этого прекрасного диалога как диалогового окна (например, из приложений консольного типа) с пустым дескриптором: компилируется прямо из окна: var dialog = new FolderSelectDialog {InitialDirectory = "C: \\", Title = "Выберите папка для импорта музыки из "}; if (dialog.Show ()) {string myFolder = dialog.FileName; }
  • 0
    Примечание: мой пример использования в качестве комментария трудно читать, поэтому: наиболее важное изменение в исходном «примере» использования: используйте запятую между InitialDirectory и Title.
1

Вы можете использовать такой код

Фильтр пустой строки. Имя файла - AnyName, но не пусто.

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;
  • 5
    Я знаю, что это старый пост, но ради любого, кто хочет попробовать это, он на самом деле не работает, если каталог, который вы хотите открыть, не имеет абсолютно никаких дочерних каталогов. Поэтому, если я хочу позволить моему пользователю перейти к папке и выбрать ее и заполнить путь к папке в каком-либо текстовом поле, пользователь никогда не сможет выбрать C: \ SomeParentDir, если существует каталог C: \ SomeParentDir \ SomeChildDir, потому что выбрав «Открыть» "просто приводит вас в дочерний каталог.
  • 0
    Хорошая попытка ... но это приводит к ужасному пользовательскому интерфейсу, так как "AnyFile" в текстовом поле просто ждет, когда пользователь переопределит свой текст ... кроме того, что пользователь также может выбирать файлы - недостаточно хорошо. но приятно попробовать ..
1

Попробуйте использовать Codeproject (кредит для Nitron):

Я думаю, что это тот же диалог, о котором вы говорите, может быть, это поможет, если вы добавите скриншот?

bool GetFolder(std::string& folderpath, const char* szCaption=NULL, HWND hOwner=NULL)
{
    bool retVal = false;

    // The BROWSEINFO struct tells the shell how it should display the dialog.
    BROWSEINFO bi;
    memset(&bi, 0, sizeof(bi));

    bi.ulFlags   = BIF_USENEWUI;
    bi.hwndOwner = hOwner;
    bi.lpszTitle = szCaption;

    // must call this if using BIF_USENEWUI
    ::OleInitialize(NULL);

    // Show the dialog and get the itemIDList for the selected folder.
    LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);

    if(pIDL != NULL)
    {
        // Create a buffer to store the path, then get the path.
        char buffer[_MAX_PATH] = {'\0'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

        // free the item id list
        CoTaskMemFree(pIDL);
    }

    ::OleUninitialize();

    return retVal;
}
  • 0
    images.google.com/… Проводите исследования, если не уверены. Я описал то, что хотел, и FolderBrowserDialog уже был дисквалифицирован как ответ.
  • 0
    «Я знаю о FolderBrowserDialog, но мне никогда не нравилось это диалоговое окно. Оно начинается слишком маленьким и не позволяет мне воспользоваться возможностью ввода пути». Проведите небольшое исследование самостоятельно - вы можете ввести путь там. В любом случае, я думаю, что это немного двусмысленный вопрос, так что удачи в этом.
Показать ещё 1 комментарий
0

Я знаю, что вопрос касался конфигурации OpenFileDialog, но, увидев, что Google привел меня сюда, я могу также указать, что если вы ТОЛЬКО ищете папки, вы должны использовать FolderBrowserDialog вместо этого, как ответил другой вопрос SO ниже

Как указать путь, используя диалог открытия файла в vb.net?

0

В Vista вы можете использовать IFileDialog с установленной опцией FOS_PICKFOLDERS. Это приведет к отображению окна OpenFileDialog, в котором вы можете выбрать папки:

var frm = (IFileDialog)(new FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= FOS_PICKFOLDERS;
frm.SetOptions(options);

if (frm.Show(owner.Handle) == S_OK) {
    IShellItem shellItem;
    frm.GetResult(out shellItem);
    IntPtr pszString;
    shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszString);
    this.Folder = Marshal.PtrToStringAuto(pszString);
}

Для старых Windows вы всегда можете прибегнуть к трюку с выбором любого файла в папке.

Рабочий пример, который работает в .NET Framework 2.0 и более поздних версиях, можно найти здесь.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню