В пользовательском элементе управления я использую RelativeSource для привязки к команде DataContext окна хостинга. Я использовал d:DataContext, чтобы указать тип DataContext как в пользовательском элементе управления, так и в окне хостинга.
В привязке команд я мог бы указать тип окна хостинга, используя AncerstorType, но не вижу способа указать тип его DataContext. Было бы неплохо иметь предупреждение во время разработки на случай, если свойство этого DataContext введено с ошибкой или не существует, а также убрать волнистые синие подчеркивания.
Добавлю к комментарию Клеменса: это означает, что вам нужно разрабатывать управляющие коды таким образом, чтобы они были полностью независимыми от DataContext. Это достигается путем введения свойства зависимости для каждого необходимого вам внешнего данных. Это был клиент вашего элемента управления, который мог использовать любой тип DataContex, который он хочет. Ему нужно только связать его свойства со свойствами элементов управления, чтобы предоставить данные. Точно так же вы привязываете коллекцию к свойству ItemsControl ItemsSource или строку к TextBloxk.Text. Эти элементы управления допускают повторное использование, поскольку они не знают своего DataContext.
Таким образом, решение вашей проблемы состоит в том, чтобы правильно спроектировать элемент управления, как описано.
Извините, но я не понимаю, почему переопределение DataContext является ошибкой программирования, если только я не злоупотребляю UserControl. Мне нравится проектировать UserControl — это представление, а связанная с ним модель представления, которая управляет взаимодействиями. Я установил DataContext пользовательского элемента управления (представления) в ViewModel, который им управляет. Я рассматриваю это как чистое разделение. Это неправильно? Если да, то почему?
«В пользовательском элементе управления я использую RelativeSource для привязки к команде DataContext окна хостинга» — это неправильный подход. Пользовательский элемент управления не должен делать предположений относительно хост-окна или его контекста данных. вместо этого вы можете объявить DP типа ICommand в пользовательском элементе управления и привязать это свойство к экземпляру в окне.
@PatriceBG Вы можете провести небольшое исследование StackOverflow о UserControls (или любых других элементах управления) с моделями частного представления, например. stackoverflow.com/questions/1939345/…. Логика управления обычно находится в коде элемента управления, а не в модели частного представления. Если вы по-прежнему хотите разделить логику управления в модель частного представления, не задавайте DataContext пользовательского элемента управления, а просто задайте контекст элемента верхнего уровня в его XAML. Таким образом, стандартное наследование значения свойства DataContext по-прежнему будет работать.
Кроме того, утверждение о том, что элемент управления знает тип своего родителя, по-прежнему неверно. Это серьезная ошибка проектирования.
@Clemens «Помимо этого, все еще неправильно, что элемент управления знает тип своего родителя». Я думал, что вся цель шаблона MVVM в противоположном. Представление должно знать о модели представления, но модель представления не должна знать о представлении. И следует избегать размещения кода в коде позади. Кроме того, не все элементы управления являются универсальными. Некоторые из них очень специализированы и предназначены только для работы в определенном контексте.
Кажется, с вашей стороны есть два заблуждения. Во-первых, тот факт, что элемент управления не должен знать о своем родительском элементе, не имеет ничего общего с MVVM. Элемент управления просто не должен ничего знать о контексте пользовательского интерфейса, в котором он используется. Как уже было сказано, он должен предоставлять привязываемые свойства, которые управляют его визуальным внешним видом и поведением.
Во-вторых, MVVM не означает отсутствия кода. Это распространенное заблуждение, но оно совершенно неверное. MVVM — это разделение задач, что означает, что логика представления может быть реализована без знания конкретного представления, использующего модель представления. Это не имеет ничего общего с реализацией контроля. Посмотрите исходный код различных элементов управления в WPF. Ни один из них, даже самый сложный, не имеет частных моделей просмотра.
Даже неясно, об одном ли мы здесь говорим, поскольку мы не видели ни строчки вашего кода. Это обсуждение основано на предположении, что ваш элемент управления внутренне устанавливает для своего DataContext модель частного представления. Это правда? Если да, то вы на неправильном пути. Создание UserControl со знанием конкретной модели представления (или, точнее, DataContext с определенным набором свойств) — это другая история. Это был бы типичный подход MVVM.
Однако элемент управления по-прежнему не должен использовать частный экземпляр такой модели представления. Модель представления будет предоставляться путем наследования значения свойства DataContext, т. е. от родительского элемента элемента управления.
Нет, пользовательский элемент управления не устанавливает внутренний контекст данных. DataContext пользовательского элемента управления привязан к XAML в главном окне. У меня есть коллекция моделей представления в главном окне, а UserControl — это пользовательский интерфейс для взаимодействия с выбранным элементом в этой коллекции. Однако есть команды, которые необходимо выполнять в контексте главного окна, поскольку они потенциально влияют на другие элементы в коллекции, поэтому я привязал команду из главного окна к кнопке в пользовательском элементе управления. Я не вижу ничего плохого в этом дизайне.
Это превращается в религиозную дискуссию, а это не то, чего я хотел. Если нет возможности объявить тип DataContext предка в XAML, пусть будет так. Я буду жить с волнистыми подчеркиваниями.
@PatriceBG DataTemplates имеет свойство DataType. Я использую это; а также объявления «Тип DataContext DesignInstance». У меня есть «пользовательские элементы управления» с шестью синхронизированными ListViews, каждый из которых имеет разные «источники»; то есть другой «контекст данных» и «тип» для элемента DataTemplates представления списка. Мы не все религиозны.
@Gerry Schmitz Да, я также широко использую тип DesignInstance. Чего я не знаю, как объявить тип DataContext предком. Я нашел, как объявить тип предка, но не тип его DataContext. Мой комментарий относительно религии заключался в том, было ли хорошим дизайном иметь пользовательский элемент управления с собственным DataContext, а не наследовать DataContext его родительского элемента, и, в моем конкретном случае, иметь кнопку в UserControl, привязанную к команде в DataContext родителя. Для меня это совершенно нормально. Если и есть недостаток, то я его не вижу.
@PatriceBG d:DataContext действителен только во время разработки. Знаете ли вы о DataContext во время выполнения?
@emoacht Да, я понимаю, что d:DataContext используется только во время разработки, я ищу эквивалент для указания типа DataContext родительского элемента. Во время выполнения все работает, пока в названии свойства нет опечатки.
@emoacht Я хотел бы получить предупреждение во время компиляции, если я ссылаюсь на несуществующее свойство, например тип. Ничего страшного, просто удобство. Как я уже писал, если это невозможно сделать, я буду с этим жить.
«Я хотел бы получить предупреждение во время компиляции, если я ссылаюсь на несуществующее свойство» --> «если есть недостаток, которого я не вижу». - Это главный момент: элементу управления невозможно узнать точный контекст дат. Если вы исправите это, введя жесткую связь с определенным типом, вы потеряете надежность, если только вы не начнете генерировать исключения, когда DataContext имеет неправильный тип. Вы теряете возможность использовать любой контекст данных в качестве источника данных для вашего элемента управления. Вы нарушаете множество распространенных и ценных принципов проектирования, таких как принцип открытия-закрытия.
Вы не можете изменить тип контекста данных, не нарушив элемент управления. Это приводит ко всем известным проблемам, которых боится каждый разработчик. Проблемы, которые, скорее всего, рано или поздно обернутся против вас. И этого так легко избежать. Если вы предоставляете необходимые данные через свойства зависимостей, вы получаете все это: безопасность типов (это то, о чем вы думаете исключительно), правильное разделение внутренних элементов управления и контекста данных, что приводит к значительному улучшению ремонтопригодности и возможности повторного использования или удобства использования в целом.
С точки зрения дизайна действительно нет смысла явно привязывать внутренние элементы к DataContext (если это предполагает ожидание определенного типа). Только представьте, насколько полезным был бы такой ListBox, который можно было бы использовать только с определенным DataContext. Надеюсь, мне удалось прояснить, почему ваш подход, заключающийся в том, чтобы сделать элемент управления зависимым от определенного типа данных, является дизайнерским запахом, которого так легко избежать.
Далее мы можем сказать, что если неизбежно, что элемент управления должен полагаться на детали реализации DataContext, то вероятность того, что эта функциональность либо принадлежит представлению (что более вероятно), либо зависящая от представления функциональность принадлежит модели представления, чрезвычайно высока. В качестве примечания: MVVM — это шаблон архитектурного проектирования уровня приложения. Это связано с нагрузкой на компоненты уровня приложения, такие как бизнес-логика.
Это не шаблон проектирования на уровне класса. Там не сказано, что каждый элемент управления является представлением и имеет модель представления. Элемент управления принадлежит представлению приложения и поэтому может ссылаться на класс функциональности модели представления приложения. MVVM также не сообщает, какой язык программирования вы используете (XAML или C#/код программной части). Подумайте об этом: если вы переместите код пользовательского интерфейса в класс модели представления, чтобы избежать кода программной части (поскольку вы считаете, что это нарушает MVVM), не нарушает ли это на самом деле MVVM? Перемещение кода пользовательского интерфейса из представления приложения в модель представления приложения никогда не может быть решением, совместимым с MVVM.
Использование свойств зависимостей в качестве источника данных и DataContext только в качестве клиентского контекста для привязки данных. Эти свойства дадут вам проверку типа компилятора (это то, что вам нужно) и надежный дизайн класса, который ценит открытие-закрытие, сокрытие информации и другие принципы проектирования.
@PatriceBG, с твоим дизайном все в порядке. Пожалуйста, не обращайте внимания на фанатиков, которые не могут ответить на вопрос WPF без лекции об их философии дизайна. К сожалению, нет, вы не можете добиться того, чего хотите. Редактор VS просто недостаточно сложен, чтобы распознать dctx относительного родительского источника.
Возможно, я сказал слишком рано. Ответ Мустафы потенциально выглядит многообещающей альтернативой.
@EmperorEto Спасибо, это прямой ответ, который я искал, если не тот, на который я надеялся. И да, ответ Мустафы решает мою главную проблему.
@PatriceBG немного не по теме, но вам может быть интересно - в MAUI вы можете указать тип контекста родительских данных относительного источника, не зная ничего о визуальном дереве. Он лазит по дереву за вас, пока не найдет что-то с dctx, соответствующим вашему типу. Это близко моему сердцу, потому что это был мой вклад в Xamarin Forms и предназначенный именно для этого сценария :) Не знаю, достаточно ли умно расширение редактора MAUI, чтобы распознать это и правильно выполнить intellisense на пути привязки, но это, безусловно, возможно. (а если бы не пиар, они бы развлеклись).
@EmperorEto Спасибо, приятно это знать. Одна из тех частей информации, которая полезна при выборе платформы для нового приложения.





Я хотел бы получить предупреждение во время компиляции, если я ссылаюсь на несуществующее свойство. [См. комментарий]
#if DEBUG
System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level =
System.Diagnostics.SourceLevels.All;
#endif
Чтобы открыть XAML Binding Failures, выберите «Отладка» > «Windows».
Разве это не работает только во время выполнения?
Работает на обоих, я этого не ожидал, Visual Studio много улучшений
Это отличная альтернатива. Это не устраняет волнистые синие подчеркивания, но приводит к сбоям привязки.
Рад, что это работает! в качестве обходного пути: I hope you keep in mind ценную информацию, предоставленную экспертами-программистами в этом долгом обсуждении, мы нигде не найдем, это требует многих лет упорного труда и знаний.
@Mustafa О, пожалуйста, Мустафа, у меня более 50 лет опыта в разработке программного обеспечения. Я изучил подводные камни и знаю, когда моя конструкция становится хрупкой. Я также узнал, когда применять принцип ЯГНИ. Мне не нужны были религиозные лекции о том, как использовать WPF. Ваш ответ был наиболее подходящим и именно тем, что мне нужно было узнать. Я благодарю вас за это.
Да, Мустафа, я согласен с @PatriceBG. Не уверен, что вы имеете в виду, но большая часть комментариев выше бесполезна. Никогда не путайте огромный # рядом с именем с мудростью или практическим опытом. Это просто означает, что у них здесь гораздо больше времени, чем у других. ВЫ предоставили очень полезный совет, который помог ФП и другим, кто задаст этот вопрос в будущем. ... скажем так, громко... люди, комментирующие выше, слишком часто больше заинтересованы в пропаганде своей конкретной философии дизайна (которая, по моему мнению, в высшей степени ошибочна), чем просто в ответах на заданные вопросы.
А еще @PatriceBG 50 лет??? Черт, я думал, что я старый! 🤣
@EmperorEto/PatriceBG, моё уважение вам, вашим словам и многолетнему опыту, GBU
@EmperorEto, да, в этом году я отмечаю 50-летие получения моего диплома инженера по компьютерным наукам в Университете Лилля (Франция) и 30-летие получения степени доктора философии в области компьютерных наук в Пенсильванском университете. И мне все еще нравится проектировать программное обеспечение, разрабатывать его и изучать новые технологии, надеюсь, еще на несколько лет. Держитесь, возраст не имеет большого значения, когда вы все еще активны и наслаждаетесь тем, что делаете.
@PatriceBG снимаю шляпу, Доктор! Мне приятно это слышать. Я тоже очень счастлив быть там, где я есть, но у меня все больше и больше случаются моменты «нынешние дети…», особенно на этом сайте. Желаю вам всего наилучшего, и если у вас есть еще вопросы по WPF, я буду начеку, надеюсь, не разжигая тотальную религиозную войну, лол.
@EmperorEto Спасибо, я ценю это. Заботиться!
DataContext родительского окна должен быть унаследован UserControl, что происходит автоматически, если вы явно не установите для DataContext UserControl что-то другое. Явная установка DataContext пользовательского элемента управления (в его XAML или коде) является распространенной ошибкой программирования, поскольку она нарушает принцип работы стандартной привязки данных.