Это только я, или 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, возможности привязки.