如何将DataGrid绑定到WPF和MVVM中的动态可变数据和用户输入 [英] How to Bind DataGrid to dynamically changeable data and User Inputs in WPF and MVVM

查看:232
本文介绍了如何将DataGrid绑定到WPF和MVVM中的动态可变数据和用户输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是WPF的新手,我想在UserControl中显示如下内容:
示例图片



我从其他来源获取数据:



列:



ID:始终存在



问题1 ... n:我有一个XML文件,例如



我要从中获取

问题专栏。

等级:始终存在



行:

strong>



每个行应仅包含文本框(某些对用户而言是只读的)。



ID列中的数据来自文件。



问题的值由用户输入。



将计算等级数据。



问题的输入值和等级的计算值与ID相关。



我尝试通过使用 DataGrid 并为问题列设置DataGridTemplateColumn来实现此目标,但并没有真正成功。我认为在这种情况下这将是正确的控件,但我真的无法弄清楚如何进行设置。



我考虑过手动构建此表 ,方法是根据数据添加问题的标签和文本框。但是随后,我的ViewModel应该了解有关违反MVVM的View的信息。



感谢和问候。



编辑:
谢谢@Ivan Furdek到目前为止的帮助!
我现在要显示问题的每个文本框和列,并可以对其进行编辑。
但是我的收藏集不会更新-.-所以我的 List< double> PointsPerProblems 停留在初始值上



这是我的XAML:

 < ItemsControl ItemsSource = {Binding PointsPerProblems,Mode = TwoWay,
UpdateSourceTrigger = PropertyChanged}>
< ItemsControl.ItemsPanel>
< ItemsPanelTemplate>
< StackPanel Orientation = Horizo​​ntal />
< / ItemsPanelTemplate>
< /ItemsControl.ItemsPanel>
< ItemsControl.ItemTemplate>
< DataTemplate>
< Border Width = 70>
< TextBox Text = {Binding Path =。,Mode = TwoWay,
UpdateSourceTrigger = PropertyChanged}
TextAlignment = Center />
< / Border>
< / DataTemplate>
< /ItemsControl.ItemTemplate>
< / ItemsControl>

我的模型:

 公共类GradingModel 
{
公共字符串MatriculationNumber {get;组; }

公开清单< double> PointsPerProblems {get;组; }

公共双级{组; }

公开Double TotalScore {get;组; }
}

以及ViewModel的特定部分:

  public ObservableCollection< GradingModel>等级
{
得到
{
返回this.gradings;
}

set
{
this.gradings = value;
this.OnPropertyChanged(nameof(this.Gradings));
}
}

公共列表< string> ProblemList
{
get
{
返回this.problemList;
}

set
{
this.problemList = value;
this.OnPropertyChanged(nameof(this.ProblemList));
}
}
private void GetGradingForm()
{
ExamRatingDTO auditRatingModel = new ExamRatingDTO();
List< StudentDTO>学生=新的List< StudentDTO>();

this.messageBoxService.ShowInfoMessage(
请选择一个包含考试评分的xml文件。,
选择考试评分文件。);
try
{
examsRatingModel = this.fileDialogService.OpenLoadFileDialog< ExamRatingDTO>();
}
catch(InvalidOperationException ex)
{
this.messageBoxService.ShowErrorMessage(请选择正确的考试成绩文件。,例如);
}

this.messageBoxService.ShowInfoMessage(
请选择一个包含学生信息的xml文件。,
选择学生信息文件。) ;
尝试
{
学生= this.fileDialogService.OpenLoadFileDialog< List< StudentDTO>>();
}
catch(InvalidOperationException ex)
{
this.messageBoxService.ShowErrorMessage(请选择正确的学生文件。,ex);
}

foreach(学生中的学生)
{
this.Gradings.Add(new GradingModel()
{
MatriculationNumber = student.MatriculationNumber.ToString(),
PointsPerProblems =新列表< double>(),
成绩= 0.0,
TotalScore = 0.0
});
}

List< string> tmpProblemList = new List< string>();

foreach(examRatingModel.PointsPerProblems中的变量问题)
{
tmpProblemList.Add(problem.ProblemName);
}

foreach(此等级中的var等级)
{
for(int i = 0; i< tmpProblemList.Count; i ++)
{
grading.PointsPerProblems.Add(0.0);
}
}

this.ProblemList = tmpProblemList;
}

编辑



Ok在答案的第二次编辑中找到了最后一个问题的解决方案



WPF:如何使带有动态列的DataGrid绑定可编辑?

解决方案

您需要将xml解析为对象列表,例如

 公共班级学生
{
public int Id {get;组; }
public List< decimal>问题分数{组; }
Public DecimalGrade
{
get
{
return ProblemScores.Average();
}
}

之后,我建议您按照以下方法进行操作必需的显示: https://blogs.msmvps.com/deborahk/populating-a-datagrid-with-dynamic-columns-in-a-silverlight-application-using-mvvm/



确保使用双向绑定,并且 UpdateSourceTrigger = PropertyChanged ,以便使更改传播回列表。



id和score列应将其IsReadOnly属性设置为true。


I´m quite new to WPF and I want to show in my UserControl something like this: Sample Image

I get data from different sources:

Columns:

ID: always present

Problem 1 ...n: I have an XML-file like this one

from which I want to get the Columns for the Problems. There can be a variable number of Problems.

Grade: always present

Rows:

Each Row should only contain Textboxes (some are read-only for the user).

The Data in the ID Column comes from a file.

The Values for the Problems are input by the user.

The Data under Grade will be calculated.

The input values for the Problems and the calculated value for Grade are related to the ID.

I tried to implement this by using a DataGrid and setting up DataGridTemplateColumn for the Problem Columns but was not really successful. I think this would be the right control in this case, but I can´t really figure out how to set this up.

I thought about building this "Table" manually, by adding Labels and Textboxes for the "Problems" depending on the Data. But then my ViewModel should know something about the View which violates MVVM.

Thanks and best regards.

EDIT: Thanks, @Ivan Furdek for your help so far! I got to show now each textbox and column for the Problems and can edit them. But my Collection won´t be updated -.- so my List<double> PointsPerProblems stays on the intialized values

Here is my XAML:

<ItemsControl ItemsSource="{Binding PointsPerProblems, Mode=TwoWay, 
             UpdateSourceTrigger=PropertyChanged}">                                            
         <ItemsControl.ItemsPanel>
             <ItemsPanelTemplate>
                 <StackPanel Orientation="Horizontal"/>
             </ItemsPanelTemplate>
         </ItemsControl.ItemsPanel>
         <ItemsControl.ItemTemplate>
             <DataTemplate>
                 <Border Width="70">
                     <TextBox Text="{Binding Path=., Mode=TwoWay,
                      UpdateSourceTrigger=PropertyChanged}"
                      TextAlignment="Center"/>
                 </Border>
             </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

My Model:

public class GradingModel
{
    public string MatriculationNumber { get; set; }

    public List<double> PointsPerProblems { get; set; }

    public double Grade { get; set; }

    public double TotalScore { get; set; }
}

And the specific parts of my ViewModel:

public ObservableCollection<GradingModel> Gradings
    {
        get
        {
            return this.gradings;
        }

        set
        {
            this.gradings = value;
            this.OnPropertyChanged(nameof(this.Gradings));
        }
    }

public List<string> ProblemList
    {
        get
        {
            return this.problemList;
        }

        set
        {
            this.problemList = value;
            this.OnPropertyChanged(nameof(this.ProblemList));
        }
    }
private void GetGradingForm()
    {
        ExamRatingDTO examRatingModel = new ExamRatingDTO();
        List<StudentDTO> students = new List<StudentDTO>();

        this.messageBoxService.ShowInfoMessage(
            "Please Select a xml-File containing the Exam Ratings.",
            "Select a Exam Rating File.");
        try
        {
           examRatingModel = this.fileDialogService.OpenLoadFileDialog<ExamRatingDTO>();
        }
        catch (InvalidOperationException ex)
        {
            this.messageBoxService.ShowErrorMessage("Please select a correct Exam Rating File.", ex);
        }

        this.messageBoxService.ShowInfoMessage(
            "Please Select a xml-File containing the Students Information.",
            "Select a Student Information File.");
        try
        {
            students = this.fileDialogService.OpenLoadFileDialog<List<StudentDTO>>();
        }
        catch (InvalidOperationException ex)
        {
            this.messageBoxService.ShowErrorMessage("Please select a correct Students File.", ex);
        }

        foreach (var student in students)
        {
            this.Gradings.Add(new GradingModel()
            {
                MatriculationNumber = student.MatriculationNumber.ToString(),
                PointsPerProblems = new List<double>(),
                Grade = 0.0,
                TotalScore = 0.0
            });
        }

        List<string> tmpProblemList = new List<string>();

        foreach (var problem in examRatingModel.PointsPerProblems)
        {
            tmpProblemList.Add(problem.ProblemName);
        }

        foreach (var grading in this.Gradings)
        {
            for (int i = 0; i < tmpProblemList.Count; i++)
            {
                grading.PointsPerProblems.Add(0.0);
            }
        }

        this.ProblemList = tmpProblemList;
    }

EDIT

Ok found the Solution for the last problem here in 2nd edit of the answer

WPF: How to make DataGrid binding with dynamic columns editable?

解决方案

You'll need to parse the xml into a list of objects like

    public class Student 
    { 
        public int Id { get; set; } 
        public List<decimal> ProblemScores { get; set; } 
        public DecimalGrade
        { 
            get
            {
               return ProblemScores.Average();
            }
        } 

After that I suggest you follow this method to get the required display: https://blogs.msmvps.com/deborahk/populating-a-datagrid-with-dynamic-columns-in-a-silverlight-application-using-mvvm/

Make sure to use two way binding, and UpdateSourceTrigger = PropertyChanged so the changes get propagated back to the list.

The columns for id and score should be have their IsReadOnly property set to true.

这篇关于如何将DataGrid绑定到WPF和MVVM中的动态可变数据和用户输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆