powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Добраться до DataContext верхнего уровня.
18 сообщений из 18, страница 1 из 1
Добраться до DataContext верхнего уровня.
    #39242198
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
                        <StackPanel Grid.Column="0" Grid.Row="0" Grid.RowSpan="2">
                            <ItemsControl ItemsSource="{Binding PhonesParsed}">
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <local:ctlPhonesParser />
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </StackPanel>


PhonesParsed это массив строк, который является свойством класса Contact, соответственно в контексте ctlPhonesParser находится строка. Как добраться до Contact, который находится в контексте StackPanel, отсюда:
Код: vbnet
1.
Private Sub ctlPhonesParser_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded

?
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39242205
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В своем время пытался погуглить, можно ли как-то получить датаконтекст иначе, то ли не смог найти, то ли нельзя, в итоге сам накропал
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
    /// <summary>
    /// Ищет для указанного элемента DataContext
    /// </summary>
    public static object FindDataContext(this DependencyObject child)
    {
      var ch = child as FrameworkElement;
      if (ch != null && ch.DataContext != null)
        return ch.DataContext;
      var parentObject = VisualTreeHelper.GetParent(child);
      if (parentObject == null)
        return null;
      return FindDataContext(parentObject);
    }
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39242233
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Примерно так же я уже делал, думал есть другой способ.
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39242348
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не понял смысла этой процедуры, для текущего элемента она возвращает его же контекст, который и так известен.

Написал свой вариант:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
    Public Function FindDataContext(Of T)(obj As FrameworkElement) As T
        If obj Is Nothing Then Return Nothing
        If Not obj.DataContext Is Nothing AndAlso TypeOf obj.DataContext Is T Then Return obj.DataContext
        Return FindDataContext(Of T)(VisualTreeHelper.GetParent(obj))
    End Function

dc = FindDataContext(Of Contact)(Me)
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39242368
Ilya81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Рекомендую в самом классе ctlPhonesParser создать свойство и назначить binding.
Код: xml
1.
<local:ctlPhonesParser SomeYourProperty="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}"/>
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39242564
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
у меня часто возникали раньше такие проблемы, потом стал более тщательно продумывать ViewModel, то есть для элемента ItemsControl'а все свойства должны быть определены в нём самом, если я хочу это отразить во View.
А для передачи команд из списка (если у элемента списка есть кнопка) существуют RoutedCommand.
Внешний вид элемента списка задается с помощью шаблона данных (DataTemplate), а это значит, что все состояния которые будет иметь этот элемент должны быть уже определены в модели представления этого элемента, чтоб не было необходимости пытаться дёргать контекст данных другого элемента через жопу.
По этому, возникает вопрос, почему у вас возникла такая необходимость, пример в студию (хотя бы примерный)
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39242613
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Архитектура у меня далека от идеального MVVM.
Вот полный код контрола:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
Public Class ctlPhonesParser

    Private Const RX_FULLPHONE As String = "[\d\s\-\(\)\+]{5,}"
    Private Const RX_SHORTPHONE As String = "0\d{3}"
    Private Const RX_INTPHONE As String = "[1-4]\d\d"

    Private Sub ctlPhonesParser_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
        If Not Me.DataContext Is Nothing Then
            Dim tb As New TextBlock, mm As MatchCollection, pm As Match
            Dim sparts() As String = Split(Me.DataContext, ",")
            tb.TextWrapping = TextWrapping.Wrap
            tb.FontSize = 12
            For x As Integer = 0 To sparts.Length - 1
                Dim s As String = Trim(sparts(x))

                If Regex.IsMatch(s, RX_FULLPHONE) Then
                    mm = Regex.Matches(s, RX_FULLPHONE)
                ElseIf Regex.IsMatch(s, RX_SHORTPHONE) Then
                    mm = Regex.Matches(s, RX_SHORTPHONE)
                ElseIf Regex.IsMatch(s, RX_INTPHONE) Then
                    mm = Regex.Matches(s, RX_INTPHONE)
                Else
                    mm = Nothing
                End If
                If mm Is Nothing Then
                    tb.Inlines.Add(New Run(s))
                Else
                    pm = Nothing
                    For Each m As Match In mm
                        If pm Is Nothing Then
                            If m.Index > 0 Then tb.Inlines.Add(New Run(Mid(s, 1, m.Index)))
                        ElseIf pm.Index + pm.Length + 1 < m.Index Then
                            tb.Inlines.Add(New Run(Mid(s, pm.Index + pm.Length + 1, m.Index - pm.Index - pm.Length)))
                        End If
                        tb.Inlines.Add(CreateHyper(m.Value))
                        pm = m
                    Next
                    If pm.Index + pm.Length < Len(s) Then tb.Inlines.Add(New Run(Mid(s, pm.Index + pm.Length + 1)))
                End If
                If sparts.Length > 1 And x <> sparts.Length - 1 Then tb.Inlines.Add(New Run(", "))
            Next
            Me.Content = tb
        End If
    End Sub

    Private Function CreateHyper(sText As String) As Hyperlink
        Dim nf As String = sText
        NormalizePhone(nf)
        Dim hl As New Hyperlink(New Run(sText)) With {.ToolTip = "Набрать номер " & nf, .Tag = nf}
        AddHandler hl.Click, AddressOf Me.HLClick
        Return hl
    End Function

    Private Sub HLClick(sender As Hyperlink, e As RoutedEventArgs)
        g_ctlMain.txtPhone.Text = CType(sender.Inlines.FirstInline, Run).Text
        Dim dc As Contact = FindDataContext(Of Contact)(Me)
        If dc Is Nothing Then
            DialNumber(New LastDialed With {.Phone = sender.Tag})
        Else
            DialNumber(New LastDialed With {.Phone = sender.Tag, .Name = dc.Name}) '<-- возникла нужда добавить в список последних набранных номеров не только номер, но и имя контакта
        End If
    End Sub
End Class

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

Вариант Ильи в данном случае похоже наиболее корректный.
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251506
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesпочему у вас возникла такая необходимостьУ меня необходимость возникла в следующем случае. Мне понадобилось ListBoxItem.IsSelected связать со свойством ViewModel для ListBoxItem-а. То есть чтобы VM конкретного элемента списка знала, выбрана она сейчас в списке или нет (а также отслеживать момент включения-выключения).

То есть в ItemTemplate мне нужна была бы связка:
Код: plaintext
{Binding IsSelected} = {Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}

при том, что IsSelected в VM не является DependencyProperty.
Я решил вопрос через AttachedProperty, но, соответственно, хендлеру требуется найти DataContext, чтобы изменить в нем нужное свойство.


Что-то не смог придумать другого решения, тебе приходилось этот вопрос решать?
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251508
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.ProRoman Mejtesпочему у вас возникла такая необходимостьУ меня необходимость возникла в следующем случае. Мне понадобилось ListBoxItem.IsSelected связать со свойством ViewModel для ListBoxItem-а. То есть чтобы VM конкретного элемента списка знала, выбрана она сейчас в списке или нет (а также отслеживать момент включения-выключения).

То есть в ItemTemplate мне нужна была бы связка:
Код: plaintext
{Binding IsSelected} = {Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}

при том, что IsSelected в VM не является DependencyProperty.
Я решил вопрос через AttachedProperty, но, соответственно, хендлеру требуется найти DataContext, чтобы изменить в нем нужное свойство.


Что-то не смог придумать другого решения, тебе приходилось этот вопрос решать?
у ListBoxItem.IsSelected свойство зависимости, зачем в VM еще одно?
Код: xml
1.
2.
3.
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding ViewModel_IsSelected}"/>
</Style>


учти, есть момент с виртуализацией, в 1 моменет времени существуют только ListBoxItem'ы области видимости + CurrentItem\SelectedItems
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251509
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: xml
1.
2.
3.
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding ViewModel_IsSelected, Mode=TwoWay}"/>
</Style>
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251568
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо.

Но ведь стиль придется прописать минимум на уровне ресурсов листбокса, то есть нельзя реализовать в пределах шаблона данных для ListItem-а...
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251927
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.Pro,

этому и не месте в шаблоне, шаблон отображается внутри ListBoxItem, в соответствующем ContentPresenter'ом, он знать не должен о том, что существует какой то там ListBoxItem.
У тебя есть шаблон CountryTemplate (к примеру), ты используешь его повсеместно, где нужно отобразить сущности соответствующего типа, всё остальное делается на уровне свойств контролов.
Если при выделении IsSelected=True нужно менять цвет (к примеру), то менять его стоит на уровне контрола, а не шаблона.
Шаблон должен быть универсальный\абстрактным от контекста (где он находится) и применим везде где встречаются сущности заданного типа, который он визуализирует.
Как он будет выглядеть ListBoxItem в разных состояниях, ты определяешь через стили, шаблоны, конверторы\DP. Не задевая сам шаблон.
то есть в DataTemplate'е использовать RelativeSource вообще не стоит, в DataTemplate лучше использовать только обычный Binding к Content'у Presenter'а (ну за исключением тех относительных источников, которые находится в рамках шаблона)
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251948
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И сама VM, и шаблон предполагают исключительное использование в контексте ListBoxItem, внешний вид его зависит от IsSelected, в частности появляются кнопки манипулирования, возможности перевода в режим редактирования и т.п. При этом при переключении IsSelected в False (пользователь кликнул по другому элементу) мне нужно выполнять код внутри VM (cвязанный с переключением режимов редактирования). То есть работа с IsSelected является неотъемлемой частью данного шаблона, без него он не имеет смысла.
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251958
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.ProИ сама VM, и шаблон предполагают исключительное использование в контексте ListBoxItem, внешний вид его зависит от IsSelected, в частности появляются кнопки манипулирования, возможности перевода в режим редактирования и т.п. При этом при переключении IsSelected в False (пользователь кликнул по другому элементу) мне нужно выполнять код внутри VM (cвязанный с переключением режимов редактирования). То есть работа с IsSelected является неотъемлемой частью данного шаблона, без него он не имеет смысла.
Через стиль ListBoxItem связываешь свойство ListBoxItem.IsSelected с ViewModel.IsSelected, в шаблоне обращаешься только к свойству ViewModel.
Если в ViewModel.IsSelected, должно даже без OnPropertyChanged(nameof(IsSelected)), работать нормально.
Код: xml
1.
2.
3.
4.
5.
6.
7.
<DataTemplate>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter TargetName="PART_Editor" Property="Visibility" Value="Visible"/>
<DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251973
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman MejtesЧерез стиль ListBoxItem связываешь свойство ListBoxItem.IsSelected с ViewModel.IsSelectedНу, собственно, об этом ты писал выше. Просто я хотел избежать определения дополнительной связки вне шаблона ListItem-а, и именно это у меня и не получилось без поиска DataContext-а.


Roman Mejtesучти, есть момент с виртуализацией, в 1 моменет времени существуют только ListBoxItem'ы области видимости + CurrentItem\SelectedItemsА где тут грабли? Ведь VM же все равно существуют для всех элементов списка.
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251985
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.ProRoman MejtesЧерез стиль ListBoxItem связываешь свойство ListBoxItem.IsSelected с ViewModel.IsSelectedНу, собственно, об этом ты писал выше. Просто я хотел избежать определения дополнительной связки вне шаблона ListItem-а, и именно это у меня и не получилось без поиска DataContext-а.


Roman Mejtesучти, есть момент с виртуализацией, в 1 моменет времени существуют только ListBoxItem'ы области видимости + CurrentItem\SelectedItemsА где тут грабли? Ведь VM же все равно существуют для всех элементов списка.
косяк в том, что если ты делаешь View, то для того, чтоб изменить свойство ListBoxItem, невидимого элемента (который находится за областью видимости), нужно сделать так, чтоб он попал в области видимости (прокрутить) и только потом менять, иначе ItemGenerator вернёт null и ты ни чего не поменяешь.
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39251994
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А, понял.
Ну в моем случае я не меняю IsSelected со стороны модели, это прерогатива пользователя.
...
Рейтинг: 0 / 0
Добраться до DataContext верхнего уровня.
    #39252143
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В итоге я сделал некий универсальный экстеншен, позволяющий связать между собой два байндинга, то есть так:
Код: xml
1.
2.
        <stw:PropertyBridge TargetProperty="{Binding IsSel}"
                            SourceProperty="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" />


Таким образом я избавился от поиска DataContext-а, хотя и использовал не нравящийся тебе RelativeSource, но, как я уже говорил, шаблон строго завязан на ListBox, так что тут не вижу ничего страшного. А PropertyBridge, полагаю, пригодится не только тут ))
...
Рейтинг: 0 / 0
18 сообщений из 18, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Добраться до DataContext верхнего уровня.
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]