Хотя создание адаптера для Source относительно понятно, к сожалению, суть второй проблемы («не оборачивая каждую строку в миниобъект») - это конфликт, встроенный в .Net и WPF.
Во-первых, WPF предоставляет вам много способов регистрации обратных вызовов «с измененными данными», но не предоставляет способа регистрации обратных вызовов, которые могли бы предоставить значение.Я имею в виду, что фаза «set» является только расширяемой, а не перехватываемой, а «get» - вообще ничем.WPF просто сохранит и вернет все данные, которые он когда-то кэшировал.
Во-вторых, в .Net string
является ... неизменным.
Теперь, если вы когда-нибудь предоставитеСтрока напрямую как безусловная привязка или как текстовый текст к любому элементу управления, вы ввернуты в тупик.Проблема в том, что WPF фактически передает только фактическое значение привязки, без информации «откуда она взялась».Базовому элементу управления будет просто дан экземпляр строки, и у него не будет никакого разумного способа изменить его, поскольку строка не может изменить себя.Вы даже не будете уведомлены о такой попытке, как со свойствами только для чтения.Более того - если вам когда-нибудь удастся перехватить такую попытку модификации, и если вы создадите правильную новую строку, WPF никогда больше не будет запрашивать у вас новое значение.Чтобы обновить пользовательский интерфейс, вам необходимо вручную, буквально, заставить WPF повторно запросить вас, например, изменив исходную привязку, чтобы она указывала в другом месте (на новое значение), или установите текст данных (на новый экземпляр).Это возможно при некотором сканировании VisualTree, так как каждый «измененный» обратный вызов дает вам DependencyObjects (Controls!), Так что вы можете сканировать вверх / вниз и изменять их свойства. Помните, что опция - я будуобратитесь к этому через минуту.
Итак, все сводится к тому, что для получения нормального двустороннего связывания вам не нужно иметь путь, вам просто нужно иметь изменяемые базовые данные.объект.Если у вас есть неизменяемое - тогда вы должны использовать привязку к изменяемому свойству, которое содержит неизменяемое значение ..
Сказав это, вы просто должны немного обернуть строки, как если вы хотите изменить их.
Другой вопрос, как это сделать.Есть много способов сделать это.Конечно, вы можете просто обернуть их, как предложили Джо и Давио (примечание для Джо: там также понадобится INotify), или вы можете попробовать сделать некоторые трюки XAML с прикрепленными свойствами и / или поведениями и / или конвертерами, чтобы сделать это длявы.Это вполне выполнимо, см., Например, мой другой пост - я показал там, как «внедрить виртуальное свойство», которое полностью извлекало данные из другого места (один преобразователь связывания + выполнял перенос на лету,вторая привязка извлекает значения из вложенной обертки).Таким образом, вы можете создать свойство «Contents» для строки, и это свойство может просто возвращать саму строку, и она будет полностью двухсторонней, без каких-либо исключений.
Но .. это НЕ будетработать в двух направлениях.
Где-то в корне вашей цепочки связывания / поведения / конвектора будет неизменная строка .Как только ваша интеллектуальная цепочка связывания с автоматическим переносом сработает с обратным вызовом «на измененном», вы получите уведомление с парой старых / новых значений.Вы сможете переназначить значения на новые и старые строки.Если вы все реализовали идеально, WPF просто использует новое значение.Если вы где-то отключились, то вам придется искусственно возвращать новое значение в пользовательский интерфейс (см. Параметры, которые я просил вас запомнить).Итак, все в порядке.Оболочки нет, старое значение было видно, оно было изменяемым, вы получили новое значение, пользовательский интерфейс отображает новое значение.Как насчет хранения?
Где-то за это время вам дали старую / новую пару значений.Если вы проанализируете их, вы получите старые / новые строки.Но как обновить старую неизменяемую строку ?Не могу сделатьДаже если сработала автоматическая упаковка, даже если сработал пользовательский интерфейс, даже если казалось, что редактирование работало, теперь вы стоите перед реальной задачей: вы вызвали модифицированный обратный вызов, и вам нужно фактически обновить этот неизменный фрагмент строки.
Во-первых,вам нужен ваш источник.Это статично?Уф.Какая удача!Так что, конечно, это пример.В измененном обратном вызове мы получили только старую + новую строку ... как получить экземпляр Source?Опции:
- сканировать VisualTree и искать его в текстовых данных и использовать все, что было найдено.
- добавить еще несколько прикрепленных свойств и привязку, чтобы привязать виртуальное свойство «Источник» ккаждую строку и прочитайте это свойство из нового значения
Хорошо выполнимо, но пахнет, но других вариантов нет.
Подождите, есть еще: не только старое / новое значение иНужен экземпляр Source!Вам также нужен ИНДЕКС РЯДА.D'о!как получить это из связанных данных?Опять же, параметры:
- сканировать VisualTree и искать его (благи) ...
- добавить еще несколько прикрепленных свойств и привязок для привязки виртуального свойства "RowIndex" к каждому (blaaergh) ...
В данный момент, хотя я вижу, что все это кажется реализуемым и на самом деле может работать должным образом , я действительно думаю, что перенос каждой строки вмаленький
public class LocalItem // + INotifyPropertyChanged
{
public int Index { get; }
public Source Source { get; }
public string Content
{
get { Source...}
set { Source... }
}
}
будет просто более удобочитаемым, элегантным и .. КОРОТКОМ для реализации.И менее подвержен ошибкам, так как больше деталей будет явным вместо привязки некоторых WPF + прикрепленной магии.