ListBox внутри ListBox, как узнать, какая кнопка нажата? - PullRequest
0 голосов
/ 06 декабря 2011

У меня есть два ListBox, один внутри другого.И оба ListBoxes будут иметь элементы, динамически добавленные в них по запросу пользователя.

Каждый раз, когда нажимается кнопка (не показана в приведенном ниже фрагменте кода), в список добавляется новый элемент.Каждый новый элемент включает в себя новый список и другие.

И у меня есть кнопки внутри внутреннего списка, по одной для каждого элемента списка внутреннего списка.

С 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 ]

1 голос
/ 07 декабря 2011

Почему бы просто не использовать QuestionsListBox.DataContext внутри ChoiceAddButton_Click напрямую?У вас есть прямой способ ссылаться на внешний ListBox из вашего кода, поскольку вы дали ему имя, а DataContext является доступным свойством.

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

Это прекрасно работает для меня вдемонстрационное решение с использованием предоставленного вами XAML.

Редактировать 2:

Извините, не думал.Button DataContext будет Choice, а не Choices коллекцией.

Ваш внутренний ListBox DataContext равен , а не a Question, это Choices.Ваш внешний TextBox имеет Question.Question в качестве DataContext.Привязка Text или ItemsSource указывает DataContext на цель привязки.Вот немного хитрого XAML, чтобы проникнуть в DataContext ссылку.

Добавьте ElementName к своему внешнему TextBox:

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

Теперь добавьте скрытый TextBlock внутриваш внутренний ListBox:

    <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 и ChoiceList (или как они там называются) и использовать их.Тогда это будет так же просто, как вызов btn.DataContext.Parent.Parent с соответствующими преобразованиями типов.Таким образом, ваш код станет проще для чтения и обслуживания.

0 голосов
/ 07 декабря 2011

Необходимо ли использовать элемент управления Button в вашем решении?Если не зафиксировано, то вы можете использовать «Элемент управления изображением», как указано ниже <Image Source="/Images/choices.add.png" Height="72" Width="72" HorizontalAlignment="Left" Stretch="Fill"/>

Если вы используете элемент управления изображением, то в сочетании с этим вы можете добавить событие изменения изменения во внутренний список (ChoicesListBox),Затем в обработчике вы можете выбрать элемент, выбранный в качестве параметра для события с измененным выбором (SelectionChangedEventArgs).

Измените поле списка и добавьте обработчик события с измененным выбором, как показано ниже

<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];
            }
    }
0 голосов
/ 07 декабря 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...