我对WPF和C#很新。我正在玩它并遇到一个问题,我觉得这对专家来说是一块蛋糕,但我不知道我做错了什么。 我正在尝试创建一个简单的DataGrid控件(在TabControl中)并将其绑定到ObservableCollection对象。 我使用他们的数据绑定概述中提供的microsoft Data Binding Demo作为我的代码的基础。
MainWindow XAML:
<Window x:Class="PetProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PetProject"
mc:Ignorable="d"
Title="PetProject" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource
Source="{Binding Source={x:Static Application.Current}, Path=Dogs}"
x:Key="DogsDataView" />
</Window.Resources>
<Grid Margin="8,8,8,8">
<TabControl>
<TabItem Header="Dogs">
<DataGrid ItemsSource="{Binding Source={StaticResource DogsDataView}}">
</DataGrid>
</TabItem>
</TabControl>
</Grid>
</Window>
代码隐藏:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace PetProject
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public partial class MainWindow : Window
{
CollectionViewSource DogsDataView;
public MainWindow()
{
InitializeComponent();
DogsDataView = (CollectionViewSource)(this.Resources["DogsDataView"]);
}
}
}
App XAML
<Application x:Class="PetProject.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PetProject"
Startup="AppStartup">
<!--StartupUri="MainWindow.xaml"-->
</Application>
代码隐藏:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace PetProject
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private ObservableCollection<Dog> dogs = new ObservableCollection<Dog>();
void AppStartup(object sender, StartupEventArgs args)
{
LoadData();
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
public ObservableCollection<Dog> Dogs
{
get { return this.dogs; }
set { this.dogs = value; }
}
private void LoadData() {
Dog Johnny = new Dog("Johnny",1325);
Dog Diamond = new Dog("Diamond",1327);
this.Dogs.Add(Johnny);
this.Dogs.Add(Diamond);
}
}
}
Dog只是一个实现INotifyPropertyChanged接口的类(现在它什么都不做):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace PetProject
{
public class Dog : INotifyPropertyChanged
{
private string name;
private string number;
public event PropertyChangedEventHandler PropertyChanged;
public Dog(string name, int number)
{
this.name = name;
this.number = number.ToString("D4");
}
protected void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
我很感激帮助理解为什么没有填充DataGrid。 此外,任何有关不良编码习惯或代码改进的建议都会非常受欢迎,因为我处于一个非常初步的经验学习阶段。 谢谢!
答案 0 :(得分:1)
您无法绑定到私人字段。您只能绑定到公共属性。就DataGrid而言,Dog
没有可显示的信息。
public class Dog : INotifyPropertyChanged
{
private string _name;
private string _number;
public Dog(string name, int number)
{
Name = name;
Number = number.ToString("D4");
}
public String Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
NotifyPropertyChanged(nameof(Name));
}
}
}
public String Number
{
get { return _number; }
set
{
if (value != _number)
{
_number = value;
NotifyPropertyChanged(nameof(Number));
}
}
}
我在您的私人字段前加上下划线,因为这是标准做法。它的标准做法是因为只有两个不同的标识符才是混淆和错误的处方。
答案 1 :(得分:1)
首先,我建议您阅读MVVM原则,然后选择一个MVVM框架与WPF一起使用。例如,MVVM light toolkit是启动和理解MVVM的不错选择。
对于您的示例,以下是您的代码的一些评论:
App
类...... Dogs
属性将位于此ViewModel中,并且会引发&#39; PropertyChanged&#39;事件在其设置器中(样本中目前不是这种情况)Window.DataContext
。StartupUri="MainWindow.xaml"
然后要加载ViewModel,您可以执行类似的操作来加载Dogs集合:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
// For test: LOAD & SET your DataContext here
//
var myDogViewmodel = new DogViewModel();
myDogViewModel.LoadData();
this.DataContext = myDogViewmodel;
}
}
您的ViewModel看起来应该是这样的:
public class DogViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Dog> _dogs;
public ObservableCollection<Dog> Dogs
{
get { return _dogs; }
set
{
_dogs = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Dogs"));
}
}
public void LoadData()
{
// ....
}
}
然后你的Dog
类还必须实现INotifuPropertyChanged接口:
public class Dog : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name;
private int _number;
public string Name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
public int Number
{
get => _number;
set
{
if (_number != value)
{
_number = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
}
}
}
}
最后,在您的MainWindow.xaml:
&GT;
<Window x:Class="PetProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PetProject"
mc:Ignorable="d"
Title="PetProject" Height="350" Width="525">
<Grid Margin="8,8,8,8">
<TabControl>
<TabItem Header="Dogs">
<DataGrid ItemsSource="{Binding Dogs}" />
</TabItem>
</TabControl>
</Grid>
它现在应该工作;)告诉我它是否清楚。熟悉MVVM ......