Search code examples
c#wpfdatagridlistboxselectedvalue

SelectedValue binding does not write write back


I'm new to wpf. Trying to add a listbox in a datagrid. Everything runs perfect but the selected value binding is not working. It's not writing the SelectedValue back. Please help.

<DataGrid Name="SoruDataGrid"  ItemsSource="{Binding Test.TestSonucuCollection}" Grid.Row="1" AutoGenerateColumns="False" Grid.ColumnSpan="2" >

        <DataGrid.Columns>
            <DataGridTextColumn Header="Id" Binding="{Binding Soru.Id}"/>

            <DataGridTextColumn Header="Soru" Binding="{Binding Soru.Text}" Width="300">
                <DataGridTextColumn.ElementStyle>
                    <Style TargetType="TextBlock">
                        <Setter Property="TextWrapping" Value="Wrap" />
                    </Style>
                </DataGridTextColumn.ElementStyle>
                <DataGridTextColumn.EditingElementStyle>
                    <Style TargetType="TextBox">
                        <Setter Property="TextWrapping" Value="Wrap" />
                        <Setter Property="AcceptsReturn" Value="true" />
                    </Style>
                </DataGridTextColumn.EditingElementStyle>
            </DataGridTextColumn>

            <DataGridTemplateColumn Header="Cevap">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ListBox SelectionMode="Single"
                                 ItemsSource="{Binding Soru.CevapCollection}" 
                                 DisplayMemberPath="Text" 
                                 SelectedValuePath="{Binding Id}"
                                 SelectedValue="{Binding CevapId, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}">

CevapModel class

using System.ComponentModel;

namespace Test.Model
{
    public class CevapModel : INotifyPropertyChanged
    {

        Cevap _cevap;

        public event PropertyChangedEventHandler PropertyChanged;

        public CevapModel()
        {
            _cevap = new Cevap();
        }

        public CevapModel(Cevap cevap)
        {
            _cevap = cevap;
        }

        public int Id
        {
            get { return _cevap.Id; }
            set
            {
                _cevap.Id = value;
                OnPropertyChanged("Id");
            }
        }

        public int SoruId
        {
            get { return _cevap.SoruId; }
            set
            {
                _cevap.SoruId = value;
                OnPropertyChanged("SoruId");
            }
        }

        public string Text
        {
            get { return _cevap.Text; }
            set
            {
                _cevap.Text = value;
                OnPropertyChanged("Text");
            }
        }

        public int Puan
        {
            get { return _cevap.Puan; }
            set
            {
                _cevap.Puan = value;
                OnPropertyChanged("Puan");
            }
        }

        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

TestSonucuModel.cs

using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace Test.Model
{
    public class TestSonucuModel : INotifyPropertyChanged
    {
        TestSonucu _testSonucu;
        SoruModel _soru;

        public event PropertyChangedEventHandler PropertyChanged;

        public TestSonucuModel()
        {
            _testSonucu = new TestSonucu();
        }

        public TestSonucuModel(TestSonucu  testSonucu)
        {
            _testSonucu = testSonucu;
        }

        public int Id
        {
            get { return _testSonucu.Id; }
            set
            {
                _testSonucu.Id = value;
                OnPropertyChanged("Id");
            }
        }

        public int TestId
        {
            get { return _testSonucu.TestId; }
            set
            {
                _testSonucu.TestId = value;
                OnPropertyChanged("TestId");
            }
        }

        public int SoruId
        {
            get { return _testSonucu.SoruId; }
            set
            {
                _testSonucu.SoruId = value;
                OnPropertyChanged("SoruId");
            }
        }

        public SoruModel Soru 
        {
            get { return _soru; }
            set
            {
                _soru = value;
                OnPropertyChanged("Soru");
            }
        }

        public int CevapId
        {
            get { return _testSonucu.CevapId; }
            set
            {
                _testSonucu.CevapId = value;
                OnPropertyChanged("CevapId");
            }
        }

        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        public static implicit operator TestSonucu(TestSonucuModel t)
        {
            return t._testSonucu;
        }
    }
}}

Solution

  • If, as you said, CevapId is a property of TestSonucu class which is the view model behind each row of your DataGrid you don't need to change binding context in this case as it will be set to instance of TestSonucu class

    <ListBox ...
        ItemsSource="{Binding Soru.CevapCollection}" 
        DisplayMemberPath="Text" 
        SelectedValuePath="Id"
        SelectedValue="{Binding Path=CevapId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    

    also SelectedValuePathshould be just Id, in the same way as you specify DisplayMemberPath which means it will take Text property of each CevapCollection item for display and Id property as value