如何使用wpf mvvm中的文本框绑定datagrid行 [英] How to bind a datagrid row with text boxes in wpf mvvm

查看:348
本文介绍了如何使用wpf mvvm中的文本框绑定datagrid行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含一些产品详细信息的DataGrid,当我双击数据网格中的特定产品时,我需要将产品细节加载到一些文本框中。



感谢提前。

解决方案

欢迎来到StackOverflow!通常人们不会回答以下问题。




  • 清楚概述您尝试做什么。

  • 所有相关代码

  • 您遇到的任何异常

  • 您使用的所有研究链接,以获得你在哪里



那就是说,我会给你一个你要求的演示。



这是XAML

 < Window x:Class =datagriddemo.MainWindow
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
xmlns:ViewModel =clr-namespace:datagriddemo
Title =MainWindowHeight =350Width =420Background =Gray>

<! - 这是我们定义XAML这里要使用
的资源的地方。如您所见,我正在导入我们的视图模型 - >
< Window.Resources>
< ViewModel:ProductGridViewModel x:Key =ProductViewModel/>
< /Window.Resources>


<! - 这是XAML的主要布局。在下面的网格中,
我将DataContext设置为上面我们定义的静态资源。
这是做什么告诉大家里面的这个网格,如果你没有定义
你自己的数据上下文,你将使用我的因为这样,所有
的元素在这个网格内可以访问公共属性
的ViewModel - >
< Grid DataContext ={StaticResource ResourceKey = ProductViewModel}>
< Grid.ColumnDefinitions>
< ColumnDefinition Width =300/>
< ColumnDefinition Width =100/>
< /Grid.ColumnDefinitions>

<! - 这是我们正在显示的datagrid。这里要注意的两件重要的事情就是ItemsSource和SelectedItem。 ItemsSource是我们要在我们的网格中显示的集合
。这是存储产品型号的位置。
SelectedProduct将是存储所选网格行的位置,因此我们可以使用下面定义的文本框来访问其数据。 - >
< DataGrid
宽度=500
Grid.Column =0
AutoGenerateColumns =False
ItemsSource ={Binding Products}
SelectedItem ={Binding SelectedProduct,Mode = TwoWay}>
< DataGrid.Columns>
< DataGridTextColumn IsReadOnly =TrueHeader =Product IDBinding ={Binding ProductID,UpdateSourceTrigger = PropertyChanged}/>
< DataGridTextColumn IsReadOnly =TrueHeader =Product NameBinding ={Binding ProductName,UpdateSourceTrigger = PropertyChanged}/>
< DataGridTextColumn IsReadOnly =TrueHeader =Total SoldBinding ={Binding TotalSold,UpdateSourceTrigger = PropertyChanged}/>
< /DataGrid.Columns>
< / DataGrid>

<! - 此堆栈面板包含我们将用于编辑我们的数据的文本框。注意
绑定指向SelectedProduct.Property。这是因为我们正在访问
中ViewModel中的SelectedProduct属性的属性。当我们编辑这些文本框时,网格
中的数据将自动更改。 - >
< StackPanel Height =100Background =WheatMargin =10Orientation =VerticalGrid.Column =1>
< TextBlock FontWeight =BoldWidth =100TextWrapping =Wrap>更新您的产品信息< / TextBlock>
< TextBox Width =100Text ={Binding SelectedProduct.ProductName,Mode = TwoWay,UpdateSourceTrigger = PropertyChanged}/>
< TextBox Width =100Text ={Binding SelectedProduct.TotalSold,Mode = TwoWay,UpdateSourceTrigger = PropertyChanged}/>
< / StackPanel>
< / Grid>
< / Window>

接下来是我们的ViewModel。如果视图是蛋糕上的结霜,那么您可以将视图模型视为布丁周围的蛋糕。您的观点模型是您的逻辑生活的地方。它会做排序,捣蛋等东西。

  using System; 
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.Linq;
使用System.Text;
使用System.Threading.Tasks;

命名空间datagriddemo
{
public class ProductGridViewModel
{
private ProductModel _SelectedProduct;
private ObservableCollection< ProductModel> _产品;


///< summary>
///注意,尽管这样更新网格,您可以在
///添加或删除元素时,不会在setter中调用onproperty
///更改... Magic?不,Observable
///集合为您调用OnPropertyChanged。
///
///注意事项:如果您做了Products = new ObservableCollection ...,则不会调用属性更改
///
///仅当你做Products.Add(你的产品)...
///< / summary>
public ObservableCollection< ProductModel>产品
{
get {return _Products; }
set {_Products = value; }
}



///< summary>
///这是网格中选择的行。当您选择新行时,它会自动更改
///,因为我们将GridItemItemItem
///设置为Mode = TwoWay
///< / summary>
public ProductModel SelectedProduct
{
get {return _SelectedProduct; }
set {_SelectedProduct = value; }
}


///< summary>
///查看模型构造函数。当视图
///被初始化时,它被自动调用,因为我们将其声明为XAML中的静态资源。
///< / summary>
public ProductGridViewModel()
{
// DONT FORGET TO NEW UP YOUR OBSERVABLE COLLECTIONS !!
Products = new ObservableCollection< ProductModel>();

//不要忘记生成数据!
GenerateProducts();
}

///< summary>
///使用此方法生成虚拟数据
///< / summary>
private void GenerateProducts()
{
for(int x = 0; x< 100; x ++)
{

this.Products.Add (新的ProductModel(x,Product#+ x,x + 50));
}
}

}
}



最后还有你的模型。这是您的实际数据。这是,这是你的布丁。

  using System; 
使用System.Collections.Generic;
使用System.ComponentModel;
使用System.Linq;
使用System.Text;
使用System.Threading.Tasks;

命名空间datagriddemo
{
public class ProductModel:INotifyPropertyChanged
{
private Int32 _ProductID;
private String _ProductName;
private Int32 _TotalSold;


///< summary>
///注意下面的属性:
///首先,属性名称与XAML
中绑定的属性一致///这是宏方案的一部分。
///
///当OnProperty更改被调用时,UI知道要搜索
///这些属性。重要的是这些都有正确的拼写
///和套管。
///< / summary>

public Int32 TotalSold
{
get {return _TotalSold; }
set
{
_TotalSold = value;
OnPropertyChanged(TotalSold);
}
}


public String ProductName
{
get {return _ProductName; }
set
{
_ProductName = value;
OnPropertyChanged(ProductName);
}
}


public Int32 ProductID
{
get {return _ProductID; }
set
{
_ProductID = value;
OnPropertyChanged(ProductID);
}
}


///< summary>
///只是正常的构造函数来加载我们的属性。
///< / summary>
///< param name =productID>< / param>
///< param name =productName>< / param>
///< param name =totalSold>< / param>
public ProductModel(Int32 productID,String productName,Int32 totalSold)
{
this.ProductID = productID;
this.ProductName = productName;
this.TotalSold = totalSold;
}

///< summary>
///这是为了更新UI
///< / summary>
public event PropertyChangedEventHandler PropertyChanged;

///< summary>
///当一个属性在此对象中更改时,如果要将其反映在
/// UI上,则需要调用此函数
///< / summary>
///< param name =propertyName>< / param>
public void OnPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if(handler!= null)
{
this.PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
}
}
}
}

最后这是预期的结果



在这第一张图像中,我们看到我们的网格加载了新的数据



< img src =https://i.stack.imgur.com/D3IJx.pngalt =enter image description here>



如果您点击一行你会看到它的数据填充在两边的两个文本框。





最后如果您更改文本框中的数据,您将看到它立即在网格中更新。





就是这样!一个完整的MVVM数据网格到文本框和后面的解决方案。希望这可以帮助。请记住我所说的关于你作为问题询问者的期望以及乐趣!欢迎使用WPF和MVVM。


I have a DataGrid which contains some Product details , i need to load the product details into some textboxes when i double click on a particular product in the datagrid.

Thanks in advance.

解决方案

Welcome to StackOverflow! Usually people won't answer questions without the following.

  • A clear summary of what you're attempting to do.
  • All of the relevant code
  • Any exceptions that you are experiencing
  • All of the research links you used in order to get where you are

That said, I will give you a demo of what you're asking for.

Here is the XAML

<Window x:Class="datagriddemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ViewModel="clr-namespace:datagriddemo"
        Title="MainWindow" Height="350" Width="420" Background="Gray">

    <!--This is where we define the resource that the XAML here is going to
    use. As you can see, I am importing our view model-->
    <Window.Resources>
        <ViewModel:ProductGridViewModel x:Key="ProductViewModel"/>
    </Window.Resources>


    <!--This is the main layout of the XAML. In the Grid below,
    I set the "DataContext" to our static resource we just defined above.
    What this does is tell everyone inside this grid, "If you don't define
    your own data context, you're going to use mine" Because of this, all
    of the elements inside this grid will have access to the public properties
    of the ViewModel-->
    <Grid DataContext="{StaticResource ResourceKey=ProductViewModel}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300"/>
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>

        <!-- This is the datagrid that we are displaying. The two important things
        to note here are "ItemsSource" and "SelectedItem". "ItemsSource" is the collection
        that we want to display in our grid. This is where are product models are stored.
        SelectedProduct is going to be where the selected grid row is stored so we can
        access its data with the text boxes defined below. -->
        <DataGrid 
            Width="500" 
            Grid.Column="0"
            AutoGenerateColumns="False"                        
            ItemsSource="{Binding Products}"
            SelectedItem="{Binding SelectedProduct, Mode=TwoWay}">
            <DataGrid.Columns>
                <DataGridTextColumn IsReadOnly="True"  Header="Product ID" Binding="{Binding ProductID, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridTextColumn IsReadOnly="True"  Header="Product Name" Binding="{Binding ProductName, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridTextColumn IsReadOnly="True"  Header="Total Sold" Binding="{Binding TotalSold, UpdateSourceTrigger=PropertyChanged}" />
            </DataGrid.Columns>
        </DataGrid>

        <!-- This stack panel contains the text boxes we are going to use to edit our data. Notice that the 
        bindings point to SelectedProduct.Property. This is because we are accessing properties inside of 
        the SelectedProduct property in our ViewModel. When we edit these text boxes the data in the grid
        will automatically change. -->
        <StackPanel Height="100" Background="Wheat" Margin="10" Orientation="Vertical" Grid.Column="1">
            <TextBlock FontWeight="Bold" Width="100" TextWrapping="Wrap">Update your product info!</TextBlock>
            <TextBox Width="100" Text="{Binding SelectedProduct.ProductName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <TextBox Width="100" Text="{Binding SelectedProduct.TotalSold, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
    </Grid>
</Window>

Next is our ViewModel. If the view is the frosting on the cake then you can think of the view model as the cake around the pudding. Your view model is where your logic lives. It will do sorting, crunching and other stuff.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace datagriddemo
{
    public class ProductGridViewModel
    {
        private ProductModel _SelectedProduct;
        private ObservableCollection<ProductModel> _Products;


        /// <summary>
        /// Notice that though this updates the grid as you
        /// add or remove elements, it doesn't call onproperty
        /// changed in the setter... Magic? Nope, Observable
        /// collections call OnPropertyChanged for you.
        /// 
        /// Caveat: They will NOT call on property changed
        /// for you if you do Products = new ObservableCollection...
        /// Only when you do Products.Add(yourProduct)...
        /// </summary>
        public ObservableCollection<ProductModel> Products
        {
            get { return _Products; }
            set { _Products = value; }
        }



        /// <summary>
        /// This is the selected row in the grid. It automatically changes
        /// when you select new rows because we set the grid SelectedItem property 
        /// to Mode=TwoWay
        /// </summary>
        public ProductModel SelectedProduct
        {
            get { return _SelectedProduct; }
            set { _SelectedProduct = value; }
        }


        /// <summary>
        /// View Models constructor. It get's called automatically when the view 
        /// is initialized because we declared it as a static resource in the XAML.
        /// </summary>
        public ProductGridViewModel()
        {
            //DONT FORGET TO NEW UP YOUR OBSERVABLE COLLECTIONS!! 
            Products = new ObservableCollection<ProductModel>();

            //Don't forget to generate the data!
            GenerateProducts();
        }

        /// <summary>
        /// Use this method to generate dummy data
        /// </summary>
        private void GenerateProducts()
        {
            for (int x = 0; x < 100; x++)
            {

                this.Products.Add(new ProductModel(x,"Product #"+x,x+50));
            }
        }

    }
}

Finally there is your Model. This is your actual data. This, yes this, is your pudding.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace datagriddemo
{
    public class ProductModel : INotifyPropertyChanged
    {
        private Int32 _ProductID;
        private String _ProductName;
        private Int32 _TotalSold;


        /// <summary>
        /// Note for the properties below:
        /// Notice that first, the property names match those bound in the XAML
        /// This is all part of the grand scheme.
        /// 
        /// When the OnProperty changed is called, the UI knows to go search for
        /// those properties. It's important that these all have the correct spelling
        /// and casing.
        /// </summary>

        public Int32 TotalSold
        {
            get { return _TotalSold; }
            set 
            { 
                _TotalSold = value;
                OnPropertyChanged("TotalSold");
            }
        }


        public String ProductName
        {
            get { return _ProductName; }
            set 
            { 
                _ProductName = value;
                OnPropertyChanged("ProductName");
            }
        }


        public Int32 ProductID
        {
            get { return _ProductID; }
            set 
            { 
                _ProductID = value;
                OnPropertyChanged("ProductID");
            }
        }


        /// <summary>
        /// Just a normal constructor to load up our properties.
        /// </summary>
        /// <param name="productID"></param>
        /// <param name="productName"></param>
        /// <param name="totalSold"></param>
        public ProductModel(Int32 productID, String productName, Int32 totalSold)
        {
            this.ProductID = productID;
            this.ProductName = productName;
            this.TotalSold = totalSold;
        }

        /// <summary>
        /// This is for updating the UI
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// When a property changes in this object, if you want it reflected on the 
        /// UI you need to call this function
        /// </summary>
        /// <param name="propertyName"></param>
        public void OnPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Finally here is the expected result

In this first image we see our grid loaded up with its new data

If you click on a row you will see it's data populate the two text boxes on the side.

Finally if you change the data in the text boxes you will see it update in the grid immediately.

And that's it! A complete MVVM datagrid to text box and back solution. Hope this helps. Please remember what I said about what is expected from you as a question asker and have fun! Welcome to WPF and MVVM.

这篇关于如何使用wpf mvvm中的文本框绑定datagrid行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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