我目前正在学习XAML& WPF并且仍在掌握数据绑定,大多只是将我的头撞在墙上直到它工作。
我在DataGrid中显示users表,并使用组合框查找' name'来自' siteid'的相应表格中的值和' roleid'值。
表单按预期工作,即它显示正确设置了组合框的数据网格 - 它也更新了用户记录 - 但是我在输出窗口中收到以下错误消息并且它让我疯狂:
System.Windows.Data错误:17:无法获取'姓名'来自''的值(类型'字符串') (键入' DataRowView')。 BindingExpression:路径=名称;的DataItem =' DataRowView的' (的HashCode = 25172842);目标元素是' ComboBox' (名称='&#39);目标财产是“NoTarget' (类型'对象')RowNotInTableException:' System.Data.RowNotInTableException:此行已从表中删除,并且没有任何数据。 BeginEdit()将允许在此行中创建新数据。
问题1:导致错误的原因是什么?
datagrid + comboboxes正确显示所以下面的XAML出了什么问题?我看不到它!
我的(简单)测试项目设置没什么特别的:
XAML:
<UserControl.Resources>
<local:TestProjectDataSet x:Key="testProjectDataSet"/>
<CollectionViewSource x:Key="usersViewSource" Source="{Binding Users, Source={StaticResource testProjectDataSet}}"/>
<CollectionViewSource x:Key="rolesViewSource" Source="{Binding Roles, Source={StaticResource testProjectDataSet}}"/>
<CollectionViewSource x:Key="sitesViewSource" Source="{Binding Sites, Source={StaticResource testProjectDataSet}}"/>
</UserControl.Resources>
<Grid Style="{StaticResource ContentRoot}" DataContext="{StaticResource usersViewSource}">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TextBlock Text="User Management:" Style="{StaticResource Heading2}" Grid.Row="0"/>
<DataGrid x:Name="UsersDataGrid" ItemsSource="{Binding}" EnableRowVirtualization="True" Grid.Row="1" RowDetailsVisibilityMode="VisibleWhenSelected" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn x:Name="idColumn" Width="SizeToHeader" IsReadOnly="True" Header="Id" Binding="{Binding Id}" />
<DataGridTextColumn x:Name="usernameColumn" Width="Auto" Header="Username" Binding="{Binding Username}"/>
<DataGridTextColumn x:Name="passwordColumn" Width="Auto" Header="Password" />
<DataGridTemplateColumn x:Name="siteNameColumn" Header="Site" Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Source={StaticResource sitesViewSource}}"
DisplayMemberPath="Code"
SelectedValuePath="Id"
SelectedValue="{Binding SiteId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="roleNameColumn" Header="Role" Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Source={StaticResource rolesViewSource}}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
SelectedValue="{Binding RoleId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Content="Save" Width="100" Height="50" Click="Button_Click" Grid.Row="2" />
</Grid>
</UserControl>
问题2:有没有更好的方法来完成所有这些?
我不得不使用DataSet,TableAdapters&amp; CollectionViewSources带有一些代码隐藏,例如
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace TestProjectUI.Pages.Admin
{
/// <summary>
/// Interaction logic for ManageUsersPage.xaml
/// </summary>
public partial class ManageUsersPage : UserControl
{
private TestProjectDataSet _database;
private TestProjectDataSetTableAdapters.UsersTableAdapter _usersAdapter;
private TestProjectDataSetTableAdapters.RolesTableAdapter _rolesAdapter;
private TestProjectDataSetTableAdapters.SitesTableAdapter _sitesAdapter;
private CollectionViewSource _usersViewSource;
private CollectionViewSource _rolesViewSource;
private CollectionViewSource _sitesViewSource;
public ManageUsersPage()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
_database = ((TestProjectDataSet)(FindResource("magazineInventoryDataSet")));
_usersAdapter = new TestProjectDataSetTableAdapters.UsersTableAdapter();
_usersAdapter.Fill(_database.Users);
_usersViewSource = ((CollectionViewSource)(FindResource("usersViewSource")));
_usersViewSource.View.MoveCurrentToFirst();
_rolesAdapter = new TestProjectDataSetTableAdapters.RolesTableAdapter();
_rolesAdapter.Fill(_database.Roles);
_rolesViewSource = ((CollectionViewSource)(FindResource("rolesViewSource")));
_rolesViewSource.View.MoveCurrentToFirst();
_sitesAdapter = new TestProjectDataSetTableAdapters.SitesTableAdapter();
_sitesAdapter.Fill(_database.Sites);
_sitesViewSource = ((CollectionViewSource)(FindResource("sitesViewSource")));
_sitesViewSource.View.MoveCurrentToFirst();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_usersAdapter.Update(_database.Users);
}
}
}
我认为可以在纯XAML中完成所有这些操作而没有代码,但到目前为止我还没有运气这么做(错误的绑定?!)
如果有人能告诉我一个更好的方法,或者改进上面的代码,那将是非常感激的。
我最近回到C#多年后Ruby,现在WPF / XAML正在踢我的屁股!
答案 0 :(得分:3)
好的,回答我自己的问题(打算删除,但不会让它帮助别人出去)。
现在似乎使用tableadapter是错误的做法。我确信它在VS2012 / EF5及更早版本中运行得很好(不知道 - 未经过测试),但我无法在VS2013 +&amp; amp; EF6 +,可能是由于我缺乏经验。
无论如何,推荐的方法是使用&#39;对象&#39;在设置数据源时。将这些对象数据源拖动到表单上时,数据绑定非常有效。创建主/明细表单或查找组合非常容易。
EF网站的“入门”部分中的以下文章对此进行了介绍,但当时我没有发现它,即使它是一个粗体字体!:
此外,我还发现以下关于PluralSight EXTREMELY极具价值的课程:
WPF Databing in Depth - by Brian Noyes
所以,TLDR:
1)使用&#39;对象&#39;在创建数据源时(在VS2013 +&amp; EF6 +中) - 不要使用&#39;数据库&#39; 2)仔细阅读任何入门文章:D
希望能帮助别人!