1

I have a ListBox with Questions and Answers which is taking data from Database. Now i want to display or edit data from selected row from 'Listbox', but i have problem how to get to this row.

Edit. Image to show what i want to do: https://i.stack.imgur.com/E4Y0S.jpg

My View:

<Window x:Class="QuizMaker.MainWindow"
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>

    <Window.Resources>
        <DataTemplate x:Key="QuestionsTemplate">
            <Grid>      
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="320" />
                    <ColumnDefinition Width="120" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="20" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Path=Question}" FontWeight="Bold" />
                <TextBlock Grid.Column="1" Text="{Binding Path=AnswerA}" />
                <TextBlock Grid.Column="2" Text="{Binding Path=AnswerB}"/>
                <TextBlock Grid.Column="3" Text="{Binding Path=AnswerC}"/>
                <TextBlock Grid.Column="4" Text="{Binding Path=AnswerD}"/>
                <TextBlock Grid.Column="5" Text="{Binding Path=RightAnswer}" FontWeight="Bold"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>

    <Grid>        
        <ListBox  DataContext="{Binding MyDataSet}" 
                  x:Name="listBox"   
                  ItemsSource="{Binding Path=QuestionTable}"
                  ItemTemplate="{StaticResource QuestionsTemplate}" 
                  SelectedItem="{Binding SelectedItemString}"             
        />

    </Grid>
</Window>

And ViewModel(I cut most of properties)

{
    class MainViewModel
    {
        private string _appPath;

        private MainModel _MainModel;


        public MainViewModel()
        {
            _MainModel = new MainModel();


            mdbFile = Path.Combine(AppDataPath, "QuestionBase.mdb");
            connString = $"Provider=Microsoft.Jet.OLEDB.4.0; Data Source={mdbFile}";
            conn = new OleDbConnection(connString);

            adapter = new OleDbDataAdapter("SELECT * FROM QuestionTable;", conn);

            MyDataSet = new DataSet();
            adapter.Fill(MyDataSet, "QuestionTable");


        }

        private void AddToDB()
        {
            conn.Open();
            OleDbCommand myCommand = new OleDbCommand("Insert INTO QuestionTable ( Question, AnswerA, AnswerB, AnswerC, AnswerD ) Values(@Question, @AnswerA, @AnswerB, @AnswerC, @AnswerD)", conn);
            myCommand.Parameters.Add("@Question", OleDbType.BSTR).Value = Question;
            myCommand.Parameters.Add("@Question", OleDbType.BSTR).Value = AnswerA;
            myCommand.Parameters.Add("@Question", OleDbType.BSTR).Value = AnswerB;
            myCommand.Parameters.Add("@Question", OleDbType.BSTR).Value = AnswerC;
            myCommand.Parameters.Add("@Question", OleDbType.BSTR).Value = AnswerD;
            myCommand.ExecuteNonQuery();
            conn.Close();
        }

        private string AppDataPath
        {
            get
            {
                if (string.IsNullOrEmpty(_appPath))
                {
                    _appPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                }
                return _appPath;
            }
        }

        public OleDbDataAdapter adapter
        {
            get
            {
                return _MainModel.adapter;
            }
            set
            {
                _MainModel.adapter = value;
                OnPropertyChanged("adapter");
            }
        }
        public DataSet MyDataSet
        {
            get
            {
                return _MainModel.MyDataSet;
            }
            set
            {
                _MainModel.MyDataSet = value;
                OnPropertyChanged("MyDataSet");
            }
        }
    public string SelectedItemString
    {
        get
        {
            return _MainModel.SelectedItemString;
        }
        set
        {
            _MainModel.SelectedItemString = value;
            OnPropertyChanged("SelectedItemString");
        }
    }


        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }





    }
}
Antt
  • 13
  • 5
  • What exactly are you asking? How to get the data from the database? – Gordon Allocman Mar 31 '16 at 20:39
  • This may be off topic, but in your `AddToDB()` method you seem to have a copy/paste bug where you're setting the `@Question` parameter five times and the other four parameters not at all. – 15ee8f99-57ff-4f92-890c-b56153 Mar 31 '16 at 20:45
  • Possible duplicate of [Change WPF DataTemplate for ListBox item if selected](http://stackoverflow.com/questions/146269/change-wpf-datatemplate-for-listbox-item-if-selected) – Tim Rutter Mar 31 '16 at 20:48
  • No, i get data from database and it's display well in listbox. Now i want to click on one row in listbox and then i want to edit(copy every field to textbox or sth) or delete selected row. – Antt Mar 31 '16 at 20:51

2 Answers2

0

Sorry I couldn't add a comment. I hope your requirement is to show the selected item's value in the TextBox and update the same value into your collection(in your case DataTable) as you change value from the TextBox. If that is your requirement change your TextBox bindings like this

<TextBox x:Name="ValueText" Text="{Binding SelectedItem.ColumnName, ElementName=listBox, UpdateSourceTrigger=PropertyChanged}" />

I don't know why you are binding SelectedItem to string type SelectedItemString property. It will create binding error as per your source.

Davy
  • 134
  • 5
0

Change your SelectedItemString property to a DataRow, and bind your other controls to that.

For example,

public DataRow SelectedItem
{
    get
    {
        return _MainModel.SelectedItem;
    }
    set
    {
        _MainModel.SelectedItem = value;
        OnPropertyChanged("SelectedItem");
    }
}

And in XAML should be something like this :

<Window x:Class="QuizMaker.MainWindow"
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>

    <Window.Resources>
        <DataTemplate x:Key="QuestionsTemplate">
            <Grid>      
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="320" />
                    <ColumnDefinition Width="120" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="20" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Path=Question}" FontWeight="Bold" />
                <TextBlock Grid.Column="1" Text="{Binding Path=AnswerA}" />
                <TextBlock Grid.Column="2" Text="{Binding Path=AnswerB}"/>
                <TextBlock Grid.Column="3" Text="{Binding Path=AnswerC}"/>
                <TextBlock Grid.Column="4" Text="{Binding Path=AnswerD}"/>
                <TextBlock Grid.Column="5" Text="{Binding Path=RightAnswer}" FontWeight="Bold"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>

    <DockPanel>   
        <ContentControl Content="{Binding SelectedItem}" 
                        ContentTemplate="{StaticResource QuestionsTemplate}" 
                        DockPanel.Dock="Top" />  

        <ListBox  DataContext="{Binding MyDataSet}" 
                  x:Name="listBox"   
                  ItemsSource="{Binding Path=QuestionTable}"
                  ItemTemplate="{StaticResource QuestionsTemplate}" 
                  SelectedItem="{Binding SelectedItem}"             
        />

    </DockPanel>
</Window>

Also if you really don't want to change the way you track your selected item, you could also bind directly to listBox.SelectedItem like Davys said

<ContentControl Content="{Binding ElementName=listBox, Path=SelectedItem}" 
                ContentTemplate="{StaticResource QuestionsTemplate}" 
                DockPanel.Dock="Top" />  
Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490