ListBox中的ListBox,我如何知道单击了哪个按钮?

时间:2011-12-06 13:10:11

标签: silverlight xaml windows-phone-7 data-binding

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

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

我在内部列表框中有按钮,一个用于内部列表框的每个列表项。

使用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>

3 个答案:

答案 0 :(得分:1)

为什么不直接在QuestionsListBox.DataContext内使用ChoiceAddButton_Click?您可以直接从代码中引用外部ListBox,因为您已为其命名,DataContext是可访问的属性。

    private void ChoiceAddButton_Click(object sender, RoutedEventArgs e)
    {
        ...
        var outerLBDataContext= QuestionsListBox.DataContext;
        ...
    }

使用您提供的XAML在演示解决方案中,这对我来说很好。

编辑2:

抱歉,没想到。 Button的{​​{1}}将是DataContext,而不是Choice集合。

您内心Choices的{​​{1}} <{1}},ListBoxDataContext。您的QuestionChoices为其TextBox。绑定Question.QuestionDataContext使Text指向绑定目标。这里有一些棘手的XAML潜入ItemsSource引用。

向您的外部DataContext添加DataContext

ElementName

现在,在内部TextBox中添加一个隐藏的TextBlock:

<TextBox Text="{Binding Question, Mode=TwoWay}" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap" ElementName="questionTextBox"/> 

最后,在事件处理程序中,您可以在树中导航以获取该引用:

ListBox

我想指出,这不是一个优雅的解决方案。然而,它是一个全UI解决方案,可能是一个有用的东西。但更好的设计是在 <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 } } } (或其他任何名称)类中包含Parent引用并使用它。然后就像使用适当的类型转换调用Choice一样简单。这样,您的代码就变得更易于阅读和维护。

答案 1 :(得分:0)

您可以在包含数据模型订阅的内部模型中添加一个事件,然后将其添加到“选择”集合中,并以相应的方式传递相关信息。

答案 2 :(得分:0)

是否有必要在解决方案中使用Button控件? 如果未修复,则可以使用下面<Image Source="/Images/choices.add.png" Height="72" Width="72" HorizontalAlignment="Left" Stretch="Fill"/>

中指定的“图像控件”

如果您使用Image控件然后与此结合使用,您可以将选择更改事件添加到内部列表框(ChoicesListBox)。然后在Handler中,您可以选择项目作为参数,并选择更改事件(SelectionChangedEventArgs)。

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

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

在page.xaml.cs中,您可以添加处理程序并访问该项目,如下所示

private void Items_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {           
            if (e.AddedItems[0] != null)
            {
//Please use the casting to the Choices items type to make use. 
                var temp = (ChoicesItemViewModel)e.AddedItems[0];
            }
    }