Twoway binding datagrid wpf xaml

不羁的心 提交于 2021-02-11 17:57:36

问题


I want to bind CLR property into datagrid Row How to Bind row binding in datagrid(Twoway Mode) CodeBehind:

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;
        }
    }

MyWindow Xaml:

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

Model Class

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;}
}

How to get particular column in datagrid field. please give any samples


回答1:


If the result you are trying to get is a table with two columns (see your image) then you obviously mixed up rows and columns I guess. You data class must have two properties: ArgumentName and ArgumentValue. You must know that each item (or each instance of MyClass) will be displayed as a row. Now, for each row create an instance of of MyClass and add it to the source collection. The bind the DataGridTextColumn.Binding property to the column's related property of the MyClass model.

The following example will show the table from your image:

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;
    }
}

MyWindow.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>

To address your comment: "i dont want to bind argumentname and argument value property. i want to bind my own CLR property. because i have 250 variables."

I don't have to understand your intentions to tell you that this is a bad idea. A class shouldn't have 250 properties. Your image shows clearly that not all 250 properties have a relation, but only two have.

In your case a datum consists of a string value e.g., "IA" and a numeric value e.g. 5. You should change your class to reflect this.
You should know that in common relational database design a data record is represented by a row. Each row is an object and each column of this row an attribute of this object. The DataGrid´ is designed with the same intention: each row is an item of the DataGrid.ItemsSource`. Each item is a separate instance. It is common to read any table e.g., a price table of products, from left to right, where each column of a row is expected to relate to a single data item e.g. product.

I highly recommend to drop your initial intention and change your data classes to reflect the relationship of your data like the example's MyTableClass reflects the relation of a data object (row) with two attributes (columns).




回答2:


What you are trying to do does not make a whole lot of sense, especially from a maintenance perspective. You have apparently 250 variables that you want to list. What if this list ever gets cut short, or extends, and you now have 2389 variables (exaggerated, but just for the point). You would be pulling your hair out trying to maintain it.

Instead, you should learn more about class structures, more probable databases too and trying to find a common pattern. Each "thing" you have is an integer-based item. But each "thing" has a corresponding purpose, or description such as your IA, IB, IC, etc.

I am proposing you CONSIDER the following. I have made an enumerator with a list of things. Example below, but I only have items for IA-IG. I also, for sample purposes, put a description associated with two of these things.

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

So, now in your code, if I have a variable based on the type of "my250Things", I can refer to it by its enum to know what it represents.

Back to your data grid. Since all your records to be presented are one row each, and showing the corresponding variable name context (IA, IB, etc) and the value it contains, I created a class. This class actually has 3 properties. A show value, a show int, and the original enum value it was created based on. Below.

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));
    }
}

Now, I want to populate a list of things I want to present to the user. Since the enum lets me know the "things" I am trying to track, I can use it to populate the list, along with it's description(s) where applicable. If none, it defaults with the string representation of the enum itself. I created a simple window "Stack1" for a demo, created a public property for binding the data list to and auto-populate based on the enum.

You will need these "using" references at the top of the window's .cs file

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

Here is the code within the window's code-behind

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();
    }
}

Finally, in the xaml of the form, I have the binding of the data grid to the list of things prepared from the enum.

    <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>

Now, within the form/window, or wherever you have your MVVM pattern defined (doubt at this point), but anyhow, however you plan on saving data, you can just cycle through the list of things, and get its respective thing and description to save wherever you plan, but that was not disclosed in your question to apply further.

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

Good luck.



来源:https://stackoverflow.com/questions/64330691/twoway-binding-datagrid-wpf-xaml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!