简体   繁体   中英

C# Wpf Binding on Textbox in Datagrid doesn't update

for my work I need to generate datagrids via code behind. The datagrids contain 2 columns: Questions (Just text, which should not be editable) and "Answers" which needs a textBox or comboBox based on an enum.

I tried to bind a list of questions (Containing the text and an answer field) to the datagrid. The question column works just fine. But the textboxes don't receive any value. I can type in them, but once I sort the datagrid all values are gone. In the itemsource of the data grid I can see that the values doesn't update at all:/

After this failure I tried this with normal datagrid in XAML but it doesn't work either. The column for answers is a DataGridTemplate Column.

Here is my xaml:

    <Window x:Class="BindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BindingTest"
        xmlns:t="clr-namespace:BindingTest;assembly=BindingTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate x:Key="AnswerTemp">
            <ContentControl>
                <ContentControl.Style>
                    <Style TargetType="ContentControl">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Typ}" Value="{x:Static t:QuestionType.Numeric}">
                                <Setter Property="ContentTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <TextBox Text="{Binding Path=Answer,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentControl.Style>
            </ContentControl>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <DataGrid x:Name="MetaDataGrid" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Questions" Binding="{Binding Text}">
                </DataGridTextColumn>
                <DataGridTemplateColumn Header="Answers" CellTemplate="{StaticResource ResourceKey=AnswerTemp}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Code behind:

// Just contains a Dictionary <string,QuestionBlock> called SeperatorList
        public static ActualPage actualPage = new ActualPage();

        public MainWindow()
        {
            InitializeComponent();

            QuestionBlock seperator = new QuestionBlock();
            seperator.Questions = new ObservableCollection<Question>();
            for (int counter = 1; counter < 11; counter++)
                seperator.Questions.Add(new Question() { Text = $"What is the {counter}. Answer?", Answer = $"{5 + counter}", Typ = QuestionType.Numeric, Names = new List<string>() { "1", "2", "3" } });
            actualPage.SeperatorList.Add("Test", seperator);
            MetaDataGrid.ItemsSource = seperator.Questions;
        }

Code in QuestionBlock:

public class QuestionBlock : INotifyPropertyChanged
    {
        private ObservableCollection<Question> _questionBlock;

        public event PropertyChangedEventHandler PropertyChanged;

        public ObservableCollection<Question> Questions
        {
            get => _questionBlock;
            set
            {
                _questionBlock = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Questions)));
            }
        }
    }

Code in Question:

public class Question : INotifyPropertyChanged
    {
        private string _text;
        private string _answer;
        private QuestionType _typ;

        public event PropertyChangedEventHandler PropertyChanged;

        public string Text
        {
            get => _text;
            set
            {
                _text = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Text)));
            }
        }

        public string Answer
        {
            get => _answer;
            set
            {
                _answer = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Answer)));
            }
        }

        public QuestionType Typ
        {
            get => _typ;
            set
            {
                _typ = value;
            }
        }
    }

What am I doing wrong here? Note: The values that should be included in the comboBox are not enum values. There are values from a string list: Any help would be appreciated :)

You should put the editable control in the CellEditingTemplate of the column:

<DataGridTemplateColumn Header="Answers" CellEditingTemplate="{StaticResource AnswerTemp}">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Answer}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

...and bind the TextBox to the Answer property of the DataContext of the ContentControl :

<DataTemplate x:Key="AnswerTemp">
    <ContentControl>
        <ContentControl.Style>
            <Style TargetType="ContentControl">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Typ}" Value="{x:Static t:QuestionType.Numeric}">
                        <Setter Property="ContentTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <TextBox Text="{Binding Path=DataContext.Answer, 
                                     RelativeSource={RelativeSource AncestorType=ContentControl}}"/>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ContentControl.Style>
    </ContentControl>
</DataTemplate>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM