Это только я, или WPF беспорядок привязки данных и пользовательских IValueConverters?

Серьезно, кажется, что каждый раз, когда я хочу, чтобы мои элементы пользовательского интерфейса разговаривали друг с другом, я в конечном итоге кодирую новый, настраиваемый IValueConverter:( Кто-то скажет мне, что я делаю это неправильно, пожалуйста!

Примеры:

  • Я хотел, чтобы кнопка включалась только в том случае, если в моем текстовом поле был допустимый URI. Отлично, время для кода UriIsValidConverter!
  • Ой, я тоже хотел отключить его, пока я что-то обрабатываю. Думаю, теперь мне нужно создать код UriIsValidAndBoolIsFalseMultiConverter!
  • Я хочу отобразить список файлов в определенном каталоге (указанном текстовым полем) внутри списка. Думаю, мне нужен конвертер DirectoryPathToFileList!
  • О, эй, мне нужны значки для каждого из этих файлов в списке. Время для преобразователя FileInfoToBitmap!
  • Я хочу, чтобы мой статус был красным, если моя строка состояния содержит "Ошибка", а зеленый - в противном случае. Yay, я получаю код StatusStringToSolidColorBrushConverter!

Я действительно думаю, что это не намного лучше, чем старый метод Windows Forms, просто проводя все вручную, используя события TextChanged (или что-то еще). Думаю, это вариант. Возможно, это то, что на самом деле делают люди, и я слишком стараюсь сделать все возможное в парадигме привязки данных?

Итак, да, пожалуйста, скажите мне, действительно ли это кодирование WPF, или если я делаю это неправильно, и если да, то что я должен делать.

Ответ 1

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

В шаблоне MVVM ваш XAML (представление) просто содержит очень простые привязки данных в ViewModel, который обрабатывает всю логику и обновляет представление через интерфейс INotifyPropertyChanged. Код для вашего третьего примера может выглядеть примерно так:

public class DirectoryManagerViewModel : INotifyPropertyChanged
{
    private string _directory;

    public string Directory
    {
        get { reutrn _directory; }
        set
        {
            if (_directory != value)
            {
                 _directory = value;
                 OnPropertyChanged("Directory");
                 if (IsValidDirectory(value))
                 {
                     PopulateFiles();
                 }
            }
        }
    }

    public ObservableCollection<FileViewModel> Files { get; private set; }

    private bool IsValidDirectory(string directory)
    {
          //return if the directory exists etc.
    }

    private bool PopulateFiles()
    {
         //Populate Files with files in directory
    }
}

Где FileViewModel - это другая модель просмотра, которая содержит имя и значок для файла.

Преимущество такого подхода заключается в том, что ViewModels можно повторно использовать с другими представлениями и другими технологиями, такими как ASP.NET или Winforms, чтобы вы не были заблокированы в стек WPF. (alos, если вы работаете в среде, где дизайнеры отвечают за внешний вид и разработчики, ответственные за поведение, это помогает определить эти границы)

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

Ответ 2

Сначала вы можете начать с чтения о Model-View-ViewModel pattern (MVVM). Джош Смит недавно опубликовал фантастическую статью не нуждаетесь в IValueConverters столько. То, как вы сейчас это делаете, вызывает очень тесную связь между вашей визуализацией и действиями вашего приложения. MVVM предназначен для развязки этих элементов.

В этом контексте ваша модель просмотра будет отслеживать состояние для вас. Ваша кнопка будет включена, если метод CanExecute для определенного ICommand в вашей модели просмотра возвращается true. Эта же концепция может обрабатывать отключение кнопки при обработке чего-либо.

Вы хотите отобразить список файлов в определенном каталоге, указанном внутри списка? Имейте модель представления DirectoryViewModel, которая будет обрабатывать представление списка файлов в представлении путем привязки к модели представления. Отображение файлов можно указать с помощью DataTemplate, указанного в XAML без кода. Эта же концепция может обрабатывать отображение значков в представлении, отображение которого может быть указано в шаблоне.

Вы хотите, чтобы ваш статус был красным, если сообщение о состоянии содержит "Ошибка" и "зеленый" в противном случае? Пусть модель представления обрабатывает определение состояния и позволяет привязке представления к этому состоянию, и теперь вам нужно только IStateConverter, чтобы преобразовать состояние в красный или зеленый соответственно (это один из многих способов решения этой проблемы в контексте MVVM).

Получите привычку хранить данные и данные отдельно от вашего представления, и ваши приложения будут слабо связаны, проще в проектировании и обслуживании, а также легче протестировать.

Ответ 3

Не знаю, ошибаетесь ли вы, просто делаете это намного сложнее, чем это должно быть!

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

  • Чтобы отобразить список файлов, я предоставляю коллекцию, содержащую этот список.
  • Если я хочу значки, объект в этой коллекции имеет свойство значка
  • Если я хочу, чтобы статус был красным или зеленым, я предоставляю свойство StatusColorbrush.

Переместив эту логику в модель представления, я получаю:

  • гораздо проще Xaml.
  • может проверить мою логику представления без представления.

В этом подходе используется одна из сильных сторон WPF, возможности привязки.