繁体   English   中英

双向绑定数据网格 wpf xaml

[英]Twoway binding datagrid wpf xaml

我想将 CLR 属性绑定到数据网格行如何在数据网格中绑定行绑定(双向模式) 在此处输入图片说明 代码隐藏:

public partial class TechnicalPropertiesU_Var : Window
    {
        public TechnicalPropertiesU_Var()
        {
            InitializeComponent();
            List<Myclass> myclassList = new List<Myclass>();
            myclassList.Add(new Myclass() { IA = 0, IB = 0, IC = 0, ID = 0, IE = 0, IF = 0, IF = 0 });
            MyGrid.ItemsSource = myclassList;
        }
    }

我的窗口 Xaml:

<Grid>
        <DataGrid x:Name="MyGrid" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Argument Name"></DataGridTextColumn>
                <DataGridTextColumn Header="Argument Value"></DataGridTextColumn>
            </DataGrid.Columns>
            
        </DataGrid>
    </Grid>

模型类

public class Myclass
{
private int iA;
private int iB;
private int iC;
private int iD;
private int iE;
private int iF;
private int iG;

public int IA{get=>iA; set=>iA =value;}
public int IB{get=>iB; set=> iB =value;}
public int IC{get=>iC; set=> iC =value;}
public int ID{get=>iD; set=> iD =value;}
public int IE{get=>iE; set=> iE =value;}
public int IF{get=>iF; set=> iF =value;}
public int IG{get=>iG; set=> iG =value;}
}

如何获取数据网格字段中的特定列。 请提供任何样品

如果您尝试获得的结果是一个包含两列的表格(请参阅您的图片),那么我猜您显然混淆了行和列。 您的数据类必须具有两个属性: ArgumentNameArgumentValue 您必须知道每个项目(或MyClass每个实例)都将显示为一行。 现在,为每一行创建MyClass一个实例并将其添加到源集合中。 DataGridTextColumn.Binding属性绑定到MyClass模型的列的相关属性。

以下示例将显示图像中的表格:

MyTableClass.cs

public class MyTableClass : INotifyPropertyChanged
{
    public MyTableClass(int argumentName, int argumentValue)
    {
        this.ArgumentName = argumentName;
        this.ArgumentValue = argumentValue;
    }

    private int argumentName;   
    private int argumentValue;

    public int ArgumentName{get=>argumentName; set{argumentName=value; NotifyPropertyChanged();}}
    public int ArgumentValue{get=>argumentValue; set{argumentValue=value; NotifyPropertyChanged();}}

    public event PropertyChangedEventHandler PropertyChanged;

    // This method is called by the Set accessor of each property.
    // The CallerMemberName attribute that is applied to the optional propertyName
    // parameter causes the property name of the caller to be substituted as an argument.
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

TechnicalPropertiesU_Var.xaml.cs

public partial class TechnicalPropertiesU_Var : Window
{
    public TechnicalPropertiesU_Var()
    {
        InitializeComponent();
        List<MyTableClass> myTableClasses = new List<MyTableClass>();

        myTableClasses.Add(new MyTableClass() { ArgumentName = "IA", ArgumentValue = 5 });
        myTableClasses.Add(new MyTableClass() { ArgumentName = "IB", ArgumentValue = 3 });
        myTableClasses.Add(new MyTableClass() { ArgumentName = "IC", ArgumentValue = 2 });
        myTableClasses.Add(new MyTableClass() { ArgumentName = "ID", ArgumentValue = 0 });
          
        MyGrid.ItemsSource = myTableClasses;
    }
}

我的窗口.xaml

<Grid>
    <DataGrid x:Name="MyGrid" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Argument Name" Binding="{Binding ArgumentName}"></DataGridTextColumn>
            <DataGridTextColumn Header="Argument Value" Binding="{Binding ArgumentValue}"></DataGridTextColumn>
        </DataGrid.Columns>
        
    </DataGrid>
</Grid>

解决您的评论:“我不想绑定参数名称和参数值属性。我想绑定我自己的 CLR 属性。因为我有 250 个变量。”

我不必理解你的意图来告诉你这是一个坏主意。 一个类不应该有 250 个属性。 您的图像清楚地表明,并非所有 250 个属性都具有关系,但只有两个具有关系。

在您的情况下,数据包含一个字符串值,例如"IA"和一个数值,例如5 您应该更改您的课程以反映这一点。
您应该知道,在常见的关系数据库设计中,数据记录由一行表示。 每行是一个对象,该行的每一列是该对象的属性。 DataGrid´ is designed with the same intention: each row is an item of the DataGrid.ItemsSource` 的DataGrid´ is designed with the same intention: each row is an item of the 每个项目都是一个单独的实例。 通常从左到右阅读任何表格,例如产品的价格表,其中一行的每一列预计与单个数据项(例如产品)相关。

我强烈建议您放弃最初的意图并更改数据类以反映数据的关系,例如示例的MyTableClass反映具有两个属性(列)的数据对象(行)的关系。

您尝试做的事情没有多大意义,尤其是从维护的角度来看。 您显然有 250 个要列出的变量。 如果此列表被缩短或扩展,并且您现在有 2389 个变量(夸大了,但只是为了重点)怎么办。 你会拔出你的头发试图保持它。

相反,您应该更多地了解类结构、更可能的数据库并尝试找到一个共同的模式。 您拥有的每个“事物”都是一个基于整数的项目。 但是每个“事物”都有相应的用途,或描述,例如您的 IA、IB、IC 等。

我建议您考虑以下事项。 我已经制作了一个带有事物列表的枚举器。 下面的示例,但我只有 IA-IG 的项目。 出于示例目的,我还提供了与其中两件事相关的描述。

public enum my250Things
{
    IA,
    IB,
    [Description("this is item C")]
    IC,
    ID,
    IE,
    [Description("testing F description")]
    IF,
    IG
}

所以,现在在你的代码中,如果我有一个基于“my250Things”类型的变量,我可以通过它的枚举来引用它以了解它代表什么。

回到你的数据网格。 由于要显示的所有记录各占一行,并显示相应的变量名称上下文(IA、IB 等)及其包含的值,因此我创建了一个类。 这个类实际上有3个属性。 一个显示值、一个显示整数和它基于的原始枚举值。 以下。

public class YourCommonThings : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _yourShowValue;
    public string YourShowValue
    {
        get { return _yourShowValue; }
        set { _yourShowValue = value;
            NotifyPropertyChanged(); }
    }

    private int _yourIntValue;
    public int YourIntValue
    {
        get { return _yourIntValue; }
        set
        {
            _yourIntValue = value;
            NotifyPropertyChanged();
        }
    }

    private my250Things _theOriginalEnum;
    public my250Things TheOriginalEnum
    {
        get { return _theOriginalEnum; }
        set
        {
            _theOriginalEnum = value;
            NotifyPropertyChanged();
        }
    }

    // This method is called by the Set accessor of each property.
    // The CallerMemberName attribute that is applied to the optional propertyName
    // parameter causes the property name of the caller to be substituted as an argument.
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

现在,我想填充我想要呈现给用户的内容列表。 由于枚举让我知道我试图跟踪的“事物”,我可以使用它来填充列表,以及它的描述(如果适用)。 如果没有,则默认使用枚举本身的字符串表示形式。 我为演示创建了一个简单的窗口“Stack1”,创建了一个公共属性,用于将数据列表绑定到枚举并根据枚举自动填充。

您将需要窗口的 .cs 文件顶部的这些“使用”引用

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;

这是窗口代码隐藏中的代码

public partial class Stack1 : Window
{

    // first, making a public property as a list of the things I want to present
    public List<YourCommonThings> BindToThisListOfThings { get; set; }

    // the name of my window is called "Stack1" and this is the constructor of the window
    public Stack1()
    {

        // start by declaring a new list of things based on the class
        BindToThisListOfThings = new List<YourCommonThings>();

        // Now, we can dynamically create a list of all the "things" you are trying to present
        // into your data grid.  In this case, I am going through an enumerator list, but could
        // also be done if the list of things was stored in a database (for example) and you 
        // queried from that, but that is a different question / option.
        foreach(my250Things oneThing in  typeof( my250Things ).GetEnumValues() )
        {
            // creating one instance of whatever your enum underlying thing is and
            // default setting the properties within the class instance for the parts
            // that are within the { }
            // the ".ToString()" portion will get your "IA","IB", ...
            // I can also add in to store the original enum value while I'm at it,
            // even though not showing to the end user in the screen.
            var justOne = new YourCommonThings
                    {   YourShowValue = oneThing.ToString(),
                        YourIntValue = 0,
                        TheOriginalEnum = oneThing };

            // and you can optionally just for sake of example purposes associate a description
            // to an enum value and pull THAT instead...
            string description = GetEnumDescription(oneThing);
            if (!string.IsNullOrWhiteSpace(description))
                justOne.YourShowValue = description;

            // Now, add to your list
            BindToThisListOfThings.Add(justOne);
        }

        // Now, you have your list prepared and ready to go for binding to
        DataContext = this;

        // and finish initializing the rest of the form.
        InitializeComponent();
    }


    // this static method is used to get the "description" component
    // out of the enumeration declaration IF such a description is declared.
    public static string GetEnumDescription(Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());

        DescriptionAttribute[] attributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];

        if (attributes != null && attributes.Any())
            return attributes.First().Description;

        return value.ToString();
    }
}

最后,在表单的 xaml 中,我将数据网格绑定到从枚举准备的事物列表。

    <DataGrid AutoGenerateColumns="False" VerticalContentAlignment="Stretch" 
        ItemsSource="{Binding BindToThisListOfThings, NotifyOnSourceUpdated=True}">

        <DataGrid.Columns>
            <DataGridTextColumn Header="Argument Name" Binding="{Binding YourShowValue}" Width="125" />

            <DataGridTextColumn Header="Argument Value" Binding="{Binding YourIntValue}" Width="125" />
        </DataGrid.Columns>
    </DataGrid>

现在,在窗体/窗口中,或任何定义了 MVVM 模式的地方(此时有疑问),但无论如何,无论您计划保存数据,您都可以循环浏览事物列表,并获取其各自的事物和描述保存您计划的任何地方,但这在您的问题中未披露以进一步申请。

public void SaveData()
{
    foreach( var oneThing in BindToThisListOfThings )
    {
        // Here, you can refer to 
        // oneThing.YourShowValue
        // oneThing.YourIntValue
        // oneThing.TheOriginalEnum
    }
}

祝你好运。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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