весь день сижу и пытаюсь понять, почему не работает привязка к свойству AvalonEdits Document. AvalonEdit - это продвинутый текстовый редактор WPF - часть проекта SharpDevelop (он будет использоваться в SharpDevelop v4 Mirador).
Итак, когда я создал простой проект - один TextEditor (настоящее имя AvalonEdits в библиотеке) и создал простой класс с одним свойством - Document, который возвращает фиктивный объект с некоторым статическим текстом, привязка работает отлично.
Однако в реальном решении я привязываю коллекцию объектов SomeEditor к TabControl. TabControl имеет DataTemplate для SomeEditor и объект TextEditor.
<TabControl Grid.Column="1" x:Name="tabControlFiles" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<TabControl.Resources>
<DataTemplate DataType="{x:Type m:SomeEditor}">
<a:TextEditor
Document="{Binding Path=Document, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource NoopConverter}, IsAsync=True}"
x:Name="avalonEdit"></a:TextEditor>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style BasedOn="{StaticResource TabItemStyle}" TargetType="{x:Type TabItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"></Setter>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Это не работает. Что я исследовал до сих пор:
- DataContext TextEditor установлен на соответствующий экземпляр SomeEditor
- Свойство TextEditors Document установлено в некоторый другой экземпляр, чем свойство SomeEditor.Document
- когда я устанавливаю точку останова на безоперационный конвертер, который прикреплен к этой привязке, он показывает мне правильное значение для документа (конвертер используется!)
Я также покопался в VisualTree, чтобы получить ссылку на TextEditor, и вызвал GetBindingExpression (TextEditor.DocumentProperty), и это ничего не вернуло
WPF выдает следующую информацию:
Информация о System.Windows.Data: 10: невозможно получить значение с помощью привязки, и действительного резервного значения не существует; используя вместо этого значение по умолчанию. BindingExpression: Путь = Документ; DataItem = 'SomeEditor' (HashCode = 26280264); целевой элемент - TextEditor (Name = 'avalonEdit'); целевым свойством является Document (тип TextDocument)
Экземпляр SomeEditor, к которому привязан, уже имеет созданную и кэшированную копию Document до того, как произойдет привязка. Геттер никогда не вызывается.
Кто-нибудь может сказать мне, что может быть не так? Почему не задано BindingExpression? Почему получатель собственности никогда не вызывается?
// редактировать: новые тесты и новые результаты
Я прочитал еще немного и установил привязку в коде позади. Когда я это делаю, это работает. Почему установка этого в XAML не работает, а выполнение того же самого в коде работает?
// edit2: код также не работает при вызове сразу после добавления объекта в наблюдаемую коллекцию, которая используется в качестве источника данных более высокого уровня (это происходит вскоре после того, как должна сработать привязка xaml). Это заставляет меня думать, что это проблема времени. Кто-нибудь может что-то сказать по этому поводу?
// edit3: Код привязки:
private List<T> GetObjectOfTypeInVisualTree<T>(DependencyObject dpob) where T : DependencyObject
{
int count = VisualTreeHelper.GetChildrenCount(dpob);
List<T> returnlist = new List<T>();
for (int i = 0; i < count; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(dpob, i);
T childAsT = child as T;
if (childAsT != null)
{
returnlist.Add(childAsT);
}
List<T> lst = GetObjectOfTypeInVisualTree<T>(child);
if (lst != null)
{
returnlist.AddRange(lst);
}
}
if (returnlist.Count > 0)
{
return returnlist;
}
return null;
}
private void RebindMenuItem_Click(object sender, RoutedEventArgs e)
{
foreach (XHTMLStudioPrototypeFileEditor ed in CurrentProject.OpenedFiles)
{
List<ContentPresenter> cps = GetObjectOfTypeInVisualTree<ContentPresenter>(tabControlFiles);
if (cps != null)
{
foreach (ContentPresenter cp in cps)
{
foreach (DataTemplate dt in tabControlFiles.Resources.Values)
{
try
{
object o = dt.FindName("avalonEdit", cp);
TextEditor ted = (TextEditor)o;
bool isDataBound = BindingOperations.IsDataBound(ted, TextEditor.DocumentProperty);
if (!isDataBound)
{
BindingOperations.SetBinding(ted, TextEditor.DocumentProperty, new Binding("Document"));
}
Console.WriteLine(isDataBound);
}
catch (Exception)
{
}
}
}
}
}
}