Можно ли перегрузить ShowDialog (), чтобы дочерняя форма возвращала информацию в качестве параметра out? - PullRequest
4 голосов
/ 11 ноября 2008

В предыдущем вопросе о как вернуть строку из диалогового окна , yapiskan предложил перегрузить метод ShowDialog () дочерней формы , чтобы включить out параметр.

У меня вопрос, является ли это хорошим подходом в C #.

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

public DialogResult ShowDialog(out string s)
{
    DialogResult result = this.ShowDialog();
    s = this.textBox1.Text;
    return result;
}

А чтобы показать форму и извлечь введенный текст, вы делаете это:

using (CustomDialog frm = new CustomDialog())
{
    string s;
    if (frm.ShowDialog(out s) == DialogResult.OK)
    {
        // do something with s
    }
}

Одно преимущество, о котором я могу подумать, заключается в том, что этот подход заставляет пользователя формы CustomDialog получать информацию, которую она содержит, через метод ShowDialog формы (а не из метода «кто знает, что называется», такого как GetMyData (). или что-то).

Ответы [ 7 ]

7 голосов
/ 11 ноября 2008

Лучше иметь публичное свойство / метод и получать информацию.

Что бы вы сделали, если бы вам потребовалась информация 3..4..5, имеющая 5 параметров? Более чистым, чтобы иметь аксессоры для получения вашей информации из диалога.

5 голосов
/ 12 ноября 2008

Это не должно быть в порядке, так как .net Framework не использует этот дизайн. В случае класса OpenFileDialog он имеет метод ShowDialog () без параметров, возвращающий DialogResult. После вызова этого метода пользователь должен получить выбранные файлы с помощью методов FileName, FileNames, SafeFileName и SafeFileNames.

Давайте предположим, что это внедрено способом out out. Мне нужно написать такой код, чтобы получить SafeFileName:

string dummyFileName;
string[] dummyFileNames;
string safeFileName;
string[] dummySafeFileNames;

myDialog.ShowDialog(out dummyFileName, out dummyFileNames, out safeFileName, out dummySafeFileNames);
2 голосов
/ 11 ноября 2008

Мой подход обычно состоит в том, чтобы написать метод, который внутренне вызывает ShowDialog, а затем соответствующим образом форматирует выходные данные. Для (надуманного) примера:

public string GetFolderName(){
    if(this.ShowDialog() == DialogResult.OK) {
        return this.FolderName.Text;
    }
    return String.Empty;
}

В большинстве случаев я делаю этот метод статичным и создаю экземпляр самого диалога изнутри тела метода - таким образом, вызывающей стороне не приходится иметь дело со ссылками на формы или с необходимостью выбирать, какое 'show' метод для вызова.

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

public struct FolderData {
    public static FolderData Empty = new FolderData();

    public string FolderName {get; set;}
    public int FilesInFolder {get; set;}
}

public FolderData GetFolderData(){
    if(this.ShowDialog() == DialogResult.OK) {
        return new FolderData {
            FolderName = this.FolderName.Text;
            FilesInFolder = int.Parse(this.FilesInFolder.Text);
        }
    }
    return FolderData.Empty;
}
2 голосов
/ 11 ноября 2008

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

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

Кроме того, подумайте о том, как разработчик использует IntelliSense для использования вашего класса. Он собирается напечатать это:

MyDialog d = new MyDialog();
d.ShowDialog(

... и при последнем нажатии клавиши появится IntelliSense, сообщая ему, что теперь он должен объявить три новые строковые переменные для хранения параметров out. Поэтому он перемещает курсор вверх и начинает печатать:

string foo;
string

... и как снова назывался второй параметр? Итак, вернитесь к открытому парену, нажмите CTRL + SPACE, о да, это bar, вернитесь к предыдущей строке и т. Д.

Проблема с использованием свойств в настраиваемом диалоговом окне заключается в том, что класс Form уже имеет миллион свойств, а три или четыре специальных свойства, которые вы создаете, будут потеряны в миксе. Чтобы это исправить, создайте класс для параметров диалога и свойство Parameters этого типа в настраиваемом диалоге. Это облегчает написание такого кода:

MyDialog d = new MyDialog();
d.Parameters.Foo = "foo";
d.Parameters.Bar = "bar";
d.Parameters.Baz = "baz";

потому что имена параметров появляются в IntelliSense, и вам не нужно объявлять переменные для хранения их значений.

2 голосов
/ 11 ноября 2008

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

1 голос
/ 11 ноября 2008

@ Musigenesis, вы действительно не хотите, чтобы клиентский код ломался при изменении вашего диалога, и использование параметра out, который действует только иногда, не очень хороший дизайн. Как говорит @Daok, когда возвращается более 1 значения, это начинает становиться грязным и ужасным.

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

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

public sealed class MySaveDialogResult
{
    public static MySaveDialogResult NonOkResult(); // Null Object pattern
    public MySaveDialogResult( string filePath ) { ... }

    // encapsulate the dialog result
    public DialogResult DialogResult { get; private set; } 
    // some property that was set in the dialog
    public string FilePath { get; private set; }
    // another property set in the dialog
    public bool AllowOVerwrite { get; private set; }
}

и ваш диалог

public MySaveDialog ...
{
    public MySaveDialogResult GetDialogResult() { .... }
}

Суть - это небольшой неизменяемый служебный класс, который также реализует шаблон нулевого объекта. Пустой объект возвращается всякий раз, когда результат диалога не был в порядке. Очевидно, что вышесказанное - это выстрел в темноте для ваших нужд, поэтому изменяйте его по своему желанию, создавайте иерархии наследования и т. Д.

Суть в том, чтобы GetDialogResult(), единственный метод в диалоге, возвращал класс, который инкапсулирует все соответствующие данные диалога.


редактирование:

@ yapiskan задается вопросом, почему бы просто не «выйти» из MyDialogResult против вызова GetDialogResult().

IMO - Очки просто:

  1. Это не соглашение
  2. Вызов метода тривиально прост, и его легче выполнять, если следовать приведенному выше аргументу «конвенция».
  3. out неудобно использовать. GetDialogResult() не заставляет вызывающую сторону писать неуклюжий код и не заставляет пользователя использовать результат диалога в момент вызова диалога.
  4. Обычно диалоговое окно не восстанавливается и не отображается повторно для получения результата, оно уже там. Show () и Hide () делают именно это.

Реальность такова, что вы торгуете вызовом метода для неуклюжего синтаксиса ShowDialog (). Вызовы методов дешевы, и вы не можете гарантировать, что вызывающая сторона будет использовать ваш параметр out больше, чем вы можете гарантировать, что они вызовут GetDialogResult (). Так зачем? Сделайте эту штуку простой в использовании или не перегружайте ShowDialog.

Может быть, все, что вы подклассифицирует, является забавным и действует по-другому, и это не применимо к вашей ситуации, но общий дизайн - формы не исчезают, когда вы нажимаете OK, они уходят, когда они находятся в Disposed ().

1 голос
/ 11 ноября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...