Silverlight ListBox在ListBox中,如何知道单击了哪个按钮?

Silverlight ListBox在ListBox中,如何知道单击了哪个按钮?,silverlight,xaml,windows-phone-7,data-binding,Silverlight,Xaml,Windows Phone 7,Data Binding,我有两个列表框,一个在另一个里面。两个列表框都会根据用户请求动态添加项目 每次单击按钮(下面的代码段中未显示)时,都会向列表框中添加一个新项。每个新项目都包括一个新的列表框和其他列表框 我在内部列表框中有按钮,每个按钮对应于内部列表框的每个列表项 使用DataContext,我可以找到绑定到内部列表项的数据,并对其进行更改,以便将更改反映到适当的列表项上 但是,我还需要对绑定到外部列表项的数据进行更改,该列表项对应于按钮。我怎么知道是哪一个 我想出了一个解决办法,我认为它不够优雅。通过对模型进行

我有两个列表框,一个在另一个里面。两个列表框都会根据用户请求动态添加项目

每次单击按钮(下面的代码段中未显示)时,都会向列表框中添加一个新项。每个新项目都包括一个新的列表框和其他列表框

我在内部列表框中有按钮,每个按钮对应于内部列表框的每个列表项

使用
DataContext
,我可以找到绑定到内部列表项的数据,并对其进行更改,以便将更改反映到适当的列表项上

但是,我还需要对绑定到外部列表项的数据进行更改,该列表项对应于按钮。我怎么知道是哪一个

我想出了一个解决办法,我认为它不够优雅。通过对模型进行更改,我可以让每个内部数据保存对外部数据的引用,这样我就可以找到绑定到外部列表项的数据。但这似乎不是一个合适的解决方案。你有什么建议吗


下面是xaml的代码片段。我把它简化了,希望它容易理解。我觉得你不必阅读全部代码

<ListBox Name="QuestionsListBox" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}" >
    <ListBox.ItemTemplate>
    <DataTemplate>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBox Text="{Binding Question, Mode=TwoWay}" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap"/>
        <ListBox Name="ChoicesListBox" ItemsSource="{Binding Choices}" Grid.Row="1" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}">
            <ListBox.ItemTemplate>
            <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0" Click="ChoiceAddButton_Click" Height="72" Width="72" HorizontalAlignment="Left" BorderBrush="Transparent">
                    <Button.Background>
                        <ImageBrush ImageSource="/Images/choices.add.png" Stretch="Fill" />
                    </Button.Background>
                </Button>
                <TextBox Text="{Binding Value, Mode=TwoWay}"  HorizontalAlignment="Stretch" Grid.Column="1" Margin="-20,0" />
            </Grid>
            </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
    </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>


在将事件添加到“选项”集合之前,您可以向包含数据模型订阅的内部模型添加事件,并以这种方式传递相关信息。

在解决方案中使用按钮控件是否有必要?? 如果未修复,则可以使用下面指定的“图像控件”

如果使用图像控件,则可以将选择更改事件添加到内部列表框(ChoicesListBox)。然后,在处理程序中,您可以在selection changed事件(SelectionChangedEventArgs)中选择作为参数的项

修改列表框并添加Selection changed事件处理程序,如下所示

<ListBox Name="ChoicesListBox" ItemsSource="{Binding Choices}" Grid.Row="1" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}" SelectionChanged="Items_SelectionChanged">

为什么不直接使用
QuestionsListBox.DataContext
ChoiceAddButton\u点击
?您有一种直接的方法从代码后面引用外部的
列表框
,因为您给了它一个名称,
DataContext
是一个可访问的属性

    private void ChoiceAddButton_Click(object sender, RoutedEventArgs e)
    {
        ...
        var outerLBDataContext= QuestionsListBox.DataContext;
        ...
    }
在使用您提供的XAML的演示解决方案中,这对我来说很好

编辑2:

对不起,我没在想。
按钮
数据上下文
将是一个
选项
,而不是
选项
集合

您的内部
列表框
数据上下文
不是
问题
,而是
选择
。您的外部
文本框
包含
问题。问题
作为其
数据上下文
。绑定
Text
ItemsSource
使
DataContext
指向绑定目标。这里有一点棘手的XAML,需要潜入
DataContext
引用

元素名称
添加到外部
文本框

<TextBox Text="{Binding Question, Mode=TwoWay}" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap" ElementName="questionTextBox"/> 
    <ListBox Name="ChoicesListBox" ItemsSource="{Binding Choices}" Grid.Row="1" HorizontalAlignment="Stretch" ItemContainerStyle="{StaticResource ListItem}"> 
        <ListBox.ItemTemplate> 
        <DataTemplate> 
        <Grid HorizontalAlignment="Stretch"> 
            <Grid.ColumnDefinitions> 
                <ColumnDefinition Width="Auto" /> 
                <ColumnDefinition Width="*" /> 
            </Grid.ColumnDefinitions> 
            <Button Grid.Column="0" Click="ChoiceAddButton_Click" Height="72" Width="72" HorizontalAlignment="Left" BorderBrush="Transparent"> 
                <Button.Background> 
                    <ImageBrush ImageSource="/Images/choices.add.png" Stretch="Fill" /> 
                </Button.Background> 
            </Button> 
            <TextBox Text="{Binding Value, Mode=TwoWay}"  HorizontalAlignment="Stretch" Grid.Column="1" Margin="-20,0" /> 
            <TextBlock Name="hiddenTextBlock" Visibility="Collapsed" DataContext="{Binding ElementName=questionTextBox, Path=DataContext}"
        </Grid> 
        </DataTemplate> 
        </ListBox.ItemTemplate> 
    </ListBox> 
最后,在事件处理程序中,您可以在树中导航以获取该引用:

    private void ChoiceAddButton_Click(object sender, RoutedEventArgs e)
    {
        Button btn = sender as Button;
        if(btn == null) return; //won't happen when this method handles the event
        Grid g = btn.Parent as Grid;
        if(g!=null) // also unlikely to fail
        {
           TextBlock tb = g.FindName("hiddenTextBlock") as TextBlock;
           if(tb!=null) // also unlikely to fail, but never hurts to be cautious
           {
               var currentQuestion = tb.DataContext;
               // now you've got the DC you want
           }
        }
    }

我想指出的是,这并不是一个真正优雅的解决方案。不过,这是一个全UI解决方案,可能是一件有用的事情。但更好的设计是在您的
选择
选择列表
(或其他名称)类中包含
父类
引用并使用它们。然后就可以通过适当的类型转换调用
btn.DataContext.Parent.Parent
。这样,您的代码就更易于阅读和维护。

您是否只需要引用外部
列表框的
DataContext
,您可以在
ChoiceAddButton\u单击
,还是更复杂的内容?@深奥的是,这就是我想要的。我会尽快尝试。非常感谢。嗨,@Esteric,这对我不起作用。QuestionsListBox.DataContext返回null。我需要的应该是相关内部列表框的
DataContext
,而不是外部列表框。对不起,我误解了你先前的评论。您有解决方案吗?如何设置
问题列表框
项目资源
,以及它绑定到什么类型的对象?在我的示例中,我将它绑定到表单构造函数中的一个
可观测集合
,因此我认为您的做法肯定有所不同。我将编辑我的答案,并建议如何获取内部
列表框
(绑定到
选项
)的
数据上下文。您需要从内部
选择添加按钮\u单击
,对吗?我不需要按钮的数据上下文。这是我节目中的一个选择。我不想要外部列表的itemsource。这是一个明显的问题集合。我想要内部列表的datacontext,这应该是一个问题。我将外部列表的itemsource设置为一组问题,内部列表的itemsource设置为一组选择(这是问题的一个成员)。我确实认为您使用的方式是最好的方式,但我的答案确实提供了一种方法,可以仅使用视图引用来执行您的请求,如果您愿意,可以自由使用。仅仅因为我认为某些东西是更好的设计,并不意味着你必须使用它,甚至它是。此外,只要您不需要使用
按钮的
DataContext
指向
选项
,就可以跳过添加隐藏控件,直接将
按钮的
DataContext
指向
问题文本框
    private void ChoiceAddButton_Click(object sender, RoutedEventArgs e)
    {
        Button btn = sender as Button;
        if(btn == null) return; //won't happen when this method handles the event
        Grid g = btn.Parent as Grid;
        if(g!=null) // also unlikely to fail
        {
           TextBlock tb = g.FindName("hiddenTextBlock") as TextBlock;
           if(tb!=null) // also unlikely to fail, but never hurts to be cautious
           {
               var currentQuestion = tb.DataContext;
               // now you've got the DC you want
           }
        }
    }