Получите объект строки ListBox с помощью кнопки, которая находится в DataTemplate.

У меня есть ListBox с DataTemplate. В шаблоне есть Button. Когда нажимается Button, я хочу выполнить некоторую логику с объектом, который является каждой строкой (в данном случае объект с именем WorkItemTypeMappings).

В theOnClick как я могу перейти от Button (object sender) к объекту, который является строкой, на которой находится кнопка?

Вот XAML моего ListBox:

<ListBox ItemsSource="{Binding Source={StaticResource WorkItemTypeMappingsCollectionView}}" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Name="lstWITypes">
    <ListBox.GroupStyle>
        <x:Static Member="GroupStyle.Default"/>
    </ListBox.GroupStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="2*"/>
                    <ColumnDefinition Width="50"/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding SourceType, Converter={StaticResource WorkItemTypeToStringConverter}}"/>
                <ComboBox Grid.Column="1" SelectedItem="{Binding DestType}" ItemsSource="{Binding WorkItemTypesForCurrentDestProject, Source={x:Static loc:MainMediator.Instance}, diagnostics:PresentationTraceSources.TraceLevel=High}" DisplayMemberPath="Name" />

                <!-- This is the button-->
                <Button Grid.Column="2" Content="{Binding PercentMapped}" 
                        Click="ManualMappingClick"/>
            </Grid>
        </DataTemplate>                                        
    </ListBox.ItemTemplate>
</ListBox>

person Vaccano    schedule 23.01.2010    source источник


Ответы (4)


В качестве альтернативы вы можете использовать Command вместо Event. Если вы привяжете свою кнопку к команде и передадите вместе с ней параметр команды, вы сможете получить элемент, связанный с этой кнопкой. Пример кода:

<!-- This is the button-->
 <Button
     Grid.Column="2"
     Content="{Binding PercentMapped}" 
     Command="SolutionNamespace:CommandClass.ButtonClickedCommand"
     CommandParameter="{Binding}" />

Я не уверен, насколько вы знакомы с командами WPF, но вы заметите, что CommandParameter привязывается к контексту без имени пути, то есть он привязывается к нужным вам WorkItemTypeMappings.

Пример кода команды:

public static SimpleCommand ButtonClickedCommand { get; set; }

static CommandClass()
{
    ButtonClickedCommand = new SimpleCommand
                           {
                               ExecuteDelegate =
                               x=> ButtonClicked(x as WorkItemTypeMappings)
                           };
}


public static ButtonClicked(WorkItemTypeMappings mappings)
{
    if(mappings != null) MessageBox.Show(mapping.PercentMapped)
}

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

SimpleCommand — это просто упрощенная реализация ICommand, можете поискать в Google, если не уверены. Я надеюсь, что это не является излишним для вашей проблемы, но вы не ошибетесь с командами WPF.

Удачи.

person Tri Q Tran    schedule 25.01.2010
comment
Хороший материал здесь. Давно хотел попробовать свои силы в командах. Это будет хорошим испытанием. Я попробую и соглашусь, если получится. - person Vaccano; 25.01.2010
comment
Это сработало фантастически! И я чувствую, что сделал это правильно. Спасибо за отличный ответ. - person Vaccano; 26.01.2010
comment
Я рад, что у вас получилось, учитывая мои минимальные фрагменты кода. Добро пожаловать. - person Tri Q Tran; 27.01.2010

Попробуйте использовать VisualTreeHelper, чтобы найти родительский элемент ListBoxItem для кнопки. Здесь можно найти несколько хороших универсальных вспомогательных функций:

Как найти элементы управления WPF по имени или типу?

так, например, вы можете найти ListBoxItem из события click с помощью такого вызова:

ListBoxItem item = UIHelper.FindVisualParent<ListBoxItem>(sender);
person sdcoder    schedule 24.01.2010
comment
Мне не нужен ListBoxItem. Мне нужны данные за ним. (Как я уже сказал в своем вопросе: с объектом, который является каждой строкой (в данном случае это объект с именем WorkItemTypeMappings) - person Vaccano; 24.01.2010
comment
ListBoxItem — это данные, стоящие за ним. Когда у вас есть ListBoxItem, вы должны просто иметь возможность преобразовать его следующим образом: WorkItemTypeMappings dataObject = item as WorkItemTypeMappings; - person sdcoder; 24.01.2010

Вы пробовали ListBox.SelectedItem?

person Muad'Dib    schedule 24.01.2010
comment
да. Однако есть возможность нажать кнопку и не выбирать элемент (проверял) - person Vaccano; 24.01.2010

Кроме того, если у вас уже есть ссылка на ListBoxControl, и у вас также есть элемент данных, представляющий строку (я предполагаю, что это так, поскольку у вас есть привязка и, следовательно, вы можете перетащить ее из DataContext на кнопку), вы можете задать ItemsContainerGenerator. ContainerFromItem, чтобы предоставить вам фактический UIElement для строки.

Генератор контейнеров элементов можно найти как свойство в самом списке. (технически элемент управления, так как именно там он определен)

person Dominic Hopton    schedule 24.01.2010
comment
Я на самом деле хочу пойти другим путем. Мне нужен элемент данных, представляющий строку. - person Vaccano; 24.01.2010