Home > Enterprise >  How to insert items inside listbox withing another listbox on button click
How to insert items inside listbox withing another listbox on button click

Time:03-09

I have a Listbox which is bound to a DataTemplate that has another Listbox on it. On DataTemplate there is a button that I want to use for adding items to DataTemplate ListBox, but I can't find a solution to do this.

Here is my listbox:

<Button Width="200" Content="Add Question" x:Name="btnAddQuestion" Click="btnAddQuestion_Click"/>
<StackPanel Orientation="Horizontal">
     <ListBox Margin="5" x:Name="lvQuestions" ItemTemplate="{StaticResource TemplateQuestionTitle}">
     </ListBox>
</StackPanel>

And this is DataTemplate:

<DataTemplate x:Key="TemplateQuestionTitle">
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <TextBox  materialDesign:HintAssist.Hint="Enter question" MinWidth="200" Style="{StaticResource MaterialDesignFloatingHintTextBox}"/>
                <Button Content=" " Command="{Binding Source={x:Reference ThisPage},Path=DataContext.Command}" />
            </StackPanel>
            <ListBox ItemsSource="{Binding MyItems}" MinHeight="50">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBox>
                        </TextBox>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </DataTemplate>

This is code behind on my page:

public partial class UIBuilder:Window
{
    private CommandVm _commandVm;     
        public UIBuilder()
        {
            InitializeComponent();      
           _commandVm = new CommandVm();
            DataContext = _commandVm;            
        }
        private void btnAddQuestion_Click(object sender, RoutedEventArgs e)
        {
            lvQuestions.Items.Add(null);
        }
}

I have implemented this code on my ViewModel in order to add items to datatemplate ListBox:

 public class CommandVm
{
    public ObservableCollection<TextBox> MyItems { get; set; }
    public CommandVm()
    {       
        MyItems = new ObservableCollection<TextBox>();
        Command = new RelayCommand<TextBox>(Execute);
    }

    private void Execute(TextBox textBox)      
    {          
        MyItems .Add(textBox);  
    }

    public ICommand Command { get; set; }
}

I use to catch the Execute() function on button " " click command, but my code doesn't add any ListBox item.

CodePudding user response:

MyItems is a property of the parent view model which means that you should bind to it like this:

<ListBox ItemsSource="{Binding DataContext.MyItems,
     RelativeSource={RelativeSource AncestorType=Window}}" MinHeight="50">

This also means that you are using one single collection of items for all questions. Besides this obvious design flaw, a view model should not contain any TextBox elements. This basically breaks what the MVVM pattern is all about.

What you should do to make this example MVVM compliant is to create a Question class that has a collection of items, e.g.:

public class Question
{
    public Question()
    {
        AddAnswerCommand = new RelayCommand<object>(Execute);
    }

    private void Execute(object obj)
    {
        Items.Add(new Answer());
    }

    public ObservableCollection<Answer> Items { get; }
        = new ObservableCollection<Answer>();

    public ICommand AddAnswerCommand { get; }
}

public class Answer { }

The window's view model should then have a collection of questions:

public class CommandVm
{
    public CommandVm()
    {
        AddQuestionCommand = new RelayCommand<object>(Execute);
    }

    public ObservableCollection<Question> Questions { get; }
        = new ObservableCollection<Question>();

    public ICommand AddQuestionCommand { get; }

    private void Execute(object obj)
    {
        Questions.Add(new Question());
    }
}

The view and the bindings could then be defined like this:

<Window.Resources>
    <DataTemplate x:Key="TemplateQuestionTitle">
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <TextBox  MinWidth="200" />
                <Button Content=" " Command="{Binding AddAnswerCommand}" />
            </StackPanel>
            <ListBox ItemsSource="{Binding Items}" MinHeight="50">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBox />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </DataTemplate>
</Window.Resources>
<StackPanel>
    <Button Width="200" Content="Add Question" Command="{Binding AddQuestionCommand}"/>
    <ListBox Margin="5"
                 ItemsSource="{Binding Questions}"
                 ItemTemplate="{StaticResource TemplateQuestionTitle}" />
</StackPanel>

This setup lets you add individual elements to each separate question.

  • Related