Гость
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Добраться до DataContext верхнего уровня. / 18 сообщений из 18, страница 1 из 1
24.05.2016, 13:45
    #39242198
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Код: 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
24.05.2016, 13:48
    #39242205
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
В своем время пытался погуглить, можно ли как-то получить датаконтекст иначе, то ли не смог найти, то ли нельзя, в итоге сам накропал
Код: 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
24.05.2016, 14:01
    #39242233
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Примерно так же я уже делал, думал есть другой способ.
...
Рейтинг: 0 / 0
24.05.2016, 15:02
    #39242348
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Не понял смысла этой процедуры, для текущего элемента она возвращает его же контекст, который и так известен.

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

Код: 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
24.05.2016, 15:11
    #39242368
Ilya81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Рекомендую в самом классе ctlPhonesParser создать свойство и назначить binding.
Код: xml
1.
<local:ctlPhonesParser SomeYourProperty="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}"/>
...
Рейтинг: 0 / 0
24.05.2016, 17:26
    #39242564
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
у меня часто возникали раньше такие проблемы, потом стал более тщательно продумывать ViewModel, то есть для элемента ItemsControl'а все свойства должны быть определены в нём самом, если я хочу это отразить во View.
А для передачи команд из списка (если у элемента списка есть кнопка) существуют RoutedCommand.
Внешний вид элемента списка задается с помощью шаблона данных (DataTemplate), а это значит, что все состояния которые будет иметь этот элемент должны быть уже определены в модели представления этого элемента, чтоб не было необходимости пытаться дёргать контекст данных другого элемента через жопу.
По этому, возникает вопрос, почему у вас возникла такая необходимость, пример в студию (хотя бы примерный)
...
Рейтинг: 0 / 0
24.05.2016, 18:04
    #39242613
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Архитектура у меня далека от идеального 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
06.06.2016, 19:57
    #39251506
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
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
06.06.2016, 20:03
    #39251508
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
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
06.06.2016, 20:04
    #39251509
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Код: xml
1.
2.
3.
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding ViewModel_IsSelected, Mode=TwoWay}"/>
</Style>
...
Рейтинг: 0 / 0
07.06.2016, 00:13
    #39251568
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Спасибо.

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

этому и не месте в шаблоне, шаблон отображается внутри ListBoxItem, в соответствующем ContentPresenter'ом, он знать не должен о том, что существует какой то там ListBoxItem.
У тебя есть шаблон CountryTemplate (к примеру), ты используешь его повсеместно, где нужно отобразить сущности соответствующего типа, всё остальное делается на уровне свойств контролов.
Если при выделении IsSelected=True нужно менять цвет (к примеру), то менять его стоит на уровне контрола, а не шаблона.
Шаблон должен быть универсальный\абстрактным от контекста (где он находится) и применим везде где встречаются сущности заданного типа, который он визуализирует.
Как он будет выглядеть ListBoxItem в разных состояниях, ты определяешь через стили, шаблоны, конверторы\DP. Не задевая сам шаблон.
то есть в DataTemplate'е использовать RelativeSource вообще не стоит, в DataTemplate лучше использовать только обычный Binding к Content'у Presenter'а (ну за исключением тех относительных источников, которые находится в рамках шаблона)
...
Рейтинг: 0 / 0
07.06.2016, 14:04
    #39251948
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
И сама VM, и шаблон предполагают исключительное использование в контексте ListBoxItem, внешний вид его зависит от IsSelected, в частности появляются кнопки манипулирования, возможности перевода в режим редактирования и т.п. При этом при переключении IsSelected в False (пользователь кликнул по другому элементу) мне нужно выполнять код внутри VM (cвязанный с переключением режимов редактирования). То есть работа с IsSelected является неотъемлемой частью данного шаблона, без него он не имеет смысла.
...
Рейтинг: 0 / 0
07.06.2016, 14:11
    #39251958
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
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
07.06.2016, 14:26
    #39251973
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Добраться до DataContext верхнего уровня.
Roman MejtesЧерез стиль ListBoxItem связываешь свойство ListBoxItem.IsSelected с ViewModel.IsSelectedНу, собственно, об этом ты писал выше. Просто я хотел избежать определения дополнительной связки вне шаблона ListItem-а, и именно это у меня и не получилось без поиска DataContext-а.


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


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


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


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