不显示WPF DataGrid DataBinding

时间:2017-12-06 14:52:35

标签: c# wpf xaml datagrid

我在当前的WPF应用程序中有一个DataGrid,我想绑定到一个包含ObservableCollection的ViewModel。用户可以在某些TextBox中输入搜索值,在输入命中后,我正在对我们的数据库执行查询,该数据库重新记录了一个记录表。从这些记录中我填充了ObservableCollection的数据。我现在正在争论数据网格没有显示数据。

我已经阅读了大量关于绑定的帖子,但我仍然遗漏了一些我认为的内容。

Product.cs

public class Product : InotifyPropertyChanged, IEditableObject
{
    public string Title { get; set; } = "";

    //public Product()
    //{

    //}
    private ProductViewModel _productViewModel = new ProductViewModel();
    public ProductViewModel productViewModel { get { return _productViewModel; } set { _productViewModel = value; } }

    public DataTable ProductsTable { get; set; }

    public void GetProducts(string filter)
    {
        //< --doing some stuff to fill the table-->

        foreach (DataRow row in ProductsTable.Rows)
        {
            productViewModel.Products.Add(new Product
            {

                Title = (string)row["TITLE"],

            });
        }
    }
}

ProductViewModel.cs

public class ProductViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private Product _SelectedProduct;
    private ObservableCollection<Product> _Products = new ObservableCollection<Product>();
    public ObservableCollection<Product> Products { get { return _Products; } set { _Products = value; } }

    public ProductViewModel()
    {
    }

    public void NotifyPropertyChanged(string propertyName)
    {

        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ProductWindow.xaml

<DataGrid 
    Name="ProductsGrid" 
    AutoGenerateColumns="False" 
    ItemsSource="{Binding Products, Mode=TwoWay, NotifyOnSourceUpdated=True}" 
    SelectedItem="{Binding SelectedProduct, Mode=TwoWay}"  
    CanUserAddRows="False" SelectionUnit="FullRow"  
    VerticalAlignment="Stretch" 
    Grid.Row="0" 
    Margin="10,10,10,10" 
    >
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Title}" Header="Title"></DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

ProductWindow.xaml.cs

    public partial class ProductWindow : Page
{
    public object DialogResult { get; private set; }
    //public ProductViewModel ProductViewModel;
    public ProductWindow()
    {

        InitializeComponent();

        DataContext = new ProductViewModel();//stackflow
        //var ProductViewModel = products.ProductViewModel;
        //ProductsGrid.DataContext = new ProductViewModel();

    }

    public ProductViewModel ViewModel => DataContext as ProductViewModel;

    private void OnKeydownHandler(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            var tb = sender as TextBox;
            Product products = new Product();
            string filter = "";//performing some ifelse to create filter
            products.GetProducts(filter);
            //ProductsGrid.DataContext = products.ProductsTable;
            //ProductsGrid.DataContext = products.productViewModel;

        }
        else if (e.Key == Key.Escape)
        {
            ProductsGrid.DataContext = null;
            foreach (TextBox tb in FindVisualChildren<TextBox>(this))
            {
                // do something with tb here
                tb.Text = "";
            }
        }
    }

}

1 个答案:

答案 0 :(得分:2)

如果DataContextProductViewModel,并且已填充Products的{​​{1}}集合,您会在ProductViewModel中看到行。我测试过了。看来您提供的视图模型可能没有任何行。

那就是说,你的设计存在问题:

DataGrid创建ProductProductViewModel创建了ProductViewModel的集合。正如我刚才所说,每个Product都会创建一个Product。这会创建一个ProductViewModel的集合。他们不断互相创造,直到你得到Product。如果您没有看到,那么您必须从其他地方调用GetProducts()。

StackOverflowException无需拥有Product的副本。这就像在汽车的每个车轮上添加汽车一样。

因此,请执行此操作:ProductViewModel拥有ProductViewModel的集合。只是。我们会调用Product来确保我们在网格中获得一些项目。你的装订很好。你只是没有填充这个系列。

GetProducts()

的ViewModels

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = new ProductViewModel();
    }

    //  Now you can call ViewModel.GetProducts(filterString) from an event handler. 
    //  It would be more "correct" to use a Command, but let's take one step at a time. 
    public ProductViewModel ViewModel => DataContext as ProductViewModel;
}

更新

问题在于:您创建了一个新的// You didn't include any implementation of IEditableObject. I presume // you can add that back in to this version of the class. public class Product : INotifyPropertyChanged, IEditableObject { // You weren't raising PropertyChanged here, or anywhere at all. // In every setter on a viewmodel, you need to do that. private string _title = ""; public string Title { get => _title; set { if (_title != value) { _title = value; NotifyPropertyChanged(nameof(Title)); } } } public Product() { } public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class ProductViewModel : INotifyPropertyChanged { public ProductViewModel() { GetProducts(""); } public event PropertyChangedEventHandler PropertyChanged; private Product _SelectedProduct; public Product SelectedProduct { get { return _SelectedProduct; } set { if (value != _SelectedProduct) { _SelectedProduct = value; NotifyPropertyChanged(nameof(SelectedProduct)); } } } public DataTable ProductsTable { get; set; } public void GetProducts(string filter) { //< --doing some stuff to fill the table--> Products.Clear(); foreach (DataRow row in ProductsTable.Rows) { Products.Add(new Product { Title = (string)row["TITLE"], }); } } private ObservableCollection<Product> _Products = new ObservableCollection<Product>(); // This setter MUST raise PropertyChanged. See the Title property above for example. public ObservableCollection<Product> Products { get { return _Products; } private set { _Products = value; } } public void NotifyPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } ,它会创建自己的Product没有任何内容绑定到该视图模型的任何属性。您填充其集合并且DataGrid不知道或不关心,因为您将其ItemsSource绑定到不同对象的属性。

因此请使用我上面的建议,尤其是窗口的ProductsViewModel属性。 我刚刚对您需要复制的ProductsViewModel.GetProducts()进行了更改:现在它在填充集合之前调用ViewModel

Products.Clear()