Еще раз немного поговорим о возможностях DataForm. Сейчас у нас нет способа добавлять или удалять записи.
Исправим эту недоработку.
Сначала рассмотрим еще раз код нашего сгенерированного сервиса.
namespace BusinessApplication1.Web.Services
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Linq;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using BusinessApplication.BLL;
// Implements application logic using the MySamplerDBEntities context.
// TODO: Add your application logic to these methods or in additional methods.
// TODO: Wire up authentication (Windows/ASP.NET Forms) and uncomment the following to disable anonymous access
// Also consider adding roles to restrict access as appropriate.
// [RequiresAuthentication]
[EnableClientAccess()]
public class DomainService1 : LinqToEntitiesDomainService<MySamplerDBEntities>
{
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Customers' query.
public IQueryable<Customer> GetCustomers()
{
return this.ObjectContext.Customers.Include("Town");
}
public void InsertCustomer(Customer customer)
{
if ((customer.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(customer, EntityState.Added);
}
else
{
this.ObjectContext.Customers.AddObject(customer);
}
}
public void UpdateCustomer(Customer currentCustomer)
{
this.ObjectContext.Customers.AttachAsModified(currentCustomer, this.ChangeSet.GetOriginal(currentCustomer));
}
public void DeleteCustomer(Customer customer)
{
if ((customer.EntityState == EntityState.Detached))
{
this.ObjectContext.Customers.Attach(customer);
}
this.ObjectContext.Customers.DeleteObject(customer);
}
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Towns' query.
public IQueryable<Town> GetTowns()
{
return this.ObjectContext.Towns;
}
public void InsertTown(Town town)
{
if ((town.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(town, EntityState.Added);
}
else
{
this.ObjectContext.Towns.AddObject(town);
}
}
public void UpdateTown(Town currentTown)
{
this.ObjectContext.Towns.AttachAsModified(currentTown, this.ChangeSet.GetOriginal(currentTown));
}
public void DeleteTown(Town town)
{
if ((town.EntityState == EntityState.Detached))
{
this.ObjectContext.Towns.Attach(town);
}
this.ObjectContext.Towns.DeleteObject(town);
}
}
}
Можно заметить, что для каждой сущности у нас имеется ряд методов: Get, Insert, Update, Delete. Руками вызвать их, похоже, нельзя (по крайней мере, врядли это нужно делать), зато DataForm умеет авточатически работать с ними.
Изменим немного xaml код формы.
<dataControls:DataForm CurrentItem="{Binding ElementName=customerDataGrid, Path=SelectedItem, Mode=TwoWay}"
AutoGenerateFields="True"
AutoCommit="False"
AutoEdit="False"
Width="400"
EditEnded="DataForm_EditEnded"
AutoGeneratingField="DataForm_AutoGeneratingField"
Name="customerDataForm"
CommandButtonsVisibility="All">
</dataControls:DataForm>
Появилось множество новых кнопок, но все они пока не работают.
Нужно еще связать Itemssource формы с данными с источником данных.
<dataControls:DataForm CurrentItem="{Binding ElementName=customerDataGrid, Path=SelectedItem, Mode=TwoWay}"
AutoGenerateFields="True"
AutoCommit="False"
AutoEdit="False"
Width="400"
EditEnded="DataForm_EditEnded"
AutoGeneratingField="DataForm_AutoGeneratingField"
Name="customerDataForm"
CommandButtonsVisibility="All"
ItemsSource="{Binding Path=Data, ElementName=customerDomainDataSource}">
</dataControls:DataForm>
И вот тут возникает забавная вещь: кнопки работают, при добавлении и удалении данных, информация в гриде меняется, а вот из базы данных строки не удаляются (зато добавление работает). Крайне забавное поведение, но опять-таки исправить это можно.
Для этого добавим следующий обработчик события DeletingItem к форме.
<dataControls:DataForm CurrentItem="{Binding ElementName=customerDataGrid, Path=SelectedItem, Mode=TwoWay}"
AutoGenerateFields="True"
AutoCommit="False"
AutoEdit="False"
Width="400"
EditEnded="DataForm_EditEnded"
AutoGeneratingField="DataForm_AutoGeneratingField"
Name="customerDataForm"
CommandButtonsVisibility="All"
ItemsSource="{Binding Path=Data, ElementName=customerDomainDataSource}"
DeletingItem="customerDataForm_DeletingItem">
</dataControls:DataForm>
private void customerDataForm_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
{
var ctx = customerDomainDataSource.DomainContext as DomainService1;
DataForm form = sender as DataForm;
form.CommitEdit();
Customer ev = form.CurrentItem as Customer;
ctx.Customers.Remove(ev);
ctx.SubmitChanges((op) =>
{
if (op.HasError)
{
MessageBox.Show(op.Error.Message);
}
}, null);
}
Теперь все работает и данные удаляются.
Весь код MainWindow.xaml.cs:
namespace BusinessApplication1
{
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using BusinessApplication1.LoginUI;
using System.Windows.Data;
using BusinessApplication1.Web.Services;
using System.ServiceModel.DomainServices.Client;
using System;
using BusinessApplication.BLL;
/// <summary>
/// <see cref="UserControl"/> class providing the main UI for the application.
/// </summary>
public partial class MainPage : UserControl
{
/// <summary>
/// Creates a new <see cref="MainPage"/> instance.
/// </summary>
public MainPage()
{
InitializeComponent();
this.loginContainer.Child = new LoginStatus();
}
/// <summary>
/// After the Frame navigates, ensure the <see cref="HyperlinkButton"/> representing the current page is selected
/// </summary>
private void ContentFrame_Navigated(object sender, NavigationEventArgs e)
{
foreach (UIElement child in LinksStackPanel.Children)
{
HyperlinkButton hb = child as HyperlinkButton;
if (hb != null && hb.NavigateUri != null)
{
if (hb.NavigateUri.ToString().Equals(e.Uri.ToString()))
{
VisualStateManager.GoToState(hb, "ActiveLink", true);
}
else
{
VisualStateManager.GoToState(hb, "InactiveLink", true);
}
}
}
}
/// <summary>
/// If an error occurs during navigation, show an error window
/// </summary>
private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
e.Handled = true;
ErrorWindow.CreateNew(e.Exception);
}
private void customerDomainDataSource_LoadedData(object sender, System.Windows.Controls.LoadedDataEventArgs e)
{
if (e.HasError)
{
System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);
e.MarkErrorAsHandled();
}
}
private void DataForm_EditEnded(object sender, DataFormEditEndedEventArgs e)
{
if (e.EditAction == DataFormEditAction.Commit)
{
customerDomainDataSource.SubmitChanges();
}
}
private void DataForm_AutoGeneratingField(object sender, DataFormAutoGeneratingFieldEventArgs e)
{
if (e.PropertyName == "Town")
{
var ctx = (customerDomainDataSource.DomainContext as DomainService1);
var townsQ = ctx.Load(ctx.GetTownsQuery(), OnGetTowns, e.Field);
}
}
public void OnGetTowns(LoadOperation loadOperation)
{
Binding binding = new Binding("Town");
binding.Mode = BindingMode.TwoWay;
var townCombobox = new ComboBox();
townCombobox.ItemsSource = loadOperation.Entities;
townCombobox.DisplayMemberPath = "Name";
townCombobox.SetBinding(ComboBox.SelectedItemProperty, binding);
var item = loadOperation.UserState as DataField;
item.Content = townCombobox;
Binding editableBinding = new Binding() { ElementName = "customerDataForm", Path = new PropertyPath("Mode"), Converter = new InverseModeConvertor() };
item.SetBinding(DataField.IsReadOnlyProperty, editableBinding);
}
private void customerDataForm_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
{
var ctx = customerDomainDataSource.DomainContext as DomainService1;
DataForm form = sender as DataForm;
form.CommitEdit();
Customer ev = form.CurrentItem as Customer;
ctx.Customers.Remove(ev);
ctx.SubmitChanges((op) =>
{
if (op.HasError)
{
MessageBox.Show(op.Error.Message);
}
}, null);
}
}
class InverseModeConvertor : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var mode = ((DataFormMode)value);
return !(mode == DataFormMode.Edit || mode == DataFormMode.AddNew);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
#endregion
}
}
MainWindow.xaml
<UserControl
x:Class="BusinessApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices" xmlns:my="clr-namespace:BusinessApplication1.Web.Services" xmlns:my1="clr-namespace:BusinessApplication.BLL">
<Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">
<Border x:Name="ContentBorder" Style="{StaticResource ContentBorderStyle}">
<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"
Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">
<navigation:Frame.UriMapper>
<uriMapper:UriMapper>
<uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>
<uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>
</uriMapper:UriMapper>
</navigation:Frame.UriMapper>
</navigation:Frame>
</Border>
<Grid Style="{StaticResource NavigationOuterGridStyle}">
<Grid x:Name="NavigationGrid" Style="{StaticResource NavigationGridStyle}">
<Border x:Name="BrandingBorder" Style="{StaticResource BrandingBorderStyle}">
<StackPanel x:Name="BrandingStackPanel" Style="{StaticResource BrandingStackPanelStyle}">
<ContentControl Style="{StaticResource LogoIcon}"/>
<TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}"
Text="{Binding ApplicationStrings.ApplicationName, Source={StaticResource ResourceWrapper}}"/>
</StackPanel>
</Border>
<Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
<StackPanel x:Name="LinksStackPanel" Style="{StaticResource LinksStackPanelStyle}">
<HyperlinkButton x:Name="Link1" Style="{StaticResource LinkStyle}"
NavigateUri="/Home" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.HomePageTitle, Source={StaticResource ResourceWrapper}}"/>
<Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>
<HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"
NavigateUri="/About" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.AboutPageTitle, Source={StaticResource ResourceWrapper}}"/>
</StackPanel>
</Border>
</Grid>
<Border x:Name="loginContainer" Style="{StaticResource LoginContainerStyle}">
<!-- LoginStatus will be added here in code behind. This is required for the designer view to work -->
</Border>
<StackPanel>
<sdk:DataGrid AutoGenerateColumns="False" ItemsSource="{Binding ElementName=customerDomainDataSource, Path=Data}" Margin="0,123,0,0" Name="customerDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" VerticalAlignment="Top" Width="400">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn x:Name="iDColumn" Binding="{Binding Path=ID, Mode=OneWay}" Header="ID" IsReadOnly="True" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="nameColumn" Binding="{Binding Path=Name}" Header="Name" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="townIDColumn" Binding="{Binding Path=TownID}" Header="Town ID" Width="SizeToHeader" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<dataControls:DataForm CurrentItem="{Binding ElementName=customerDataGrid, Path=SelectedItem, Mode=TwoWay}"
AutoGenerateFields="True"
AutoCommit="False"
AutoEdit="False"
Width="400"
EditEnded="DataForm_EditEnded"
AutoGeneratingField="DataForm_AutoGeneratingField"
Name="customerDataForm"
CommandButtonsVisibility="All"
ItemsSource="{Binding Path=Data, ElementName=customerDomainDataSource}"
DeletingItem="customerDataForm_DeletingItem">
</dataControls:DataForm>
</StackPanel>
</Grid>
<riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my1:Customer, CreateList=true}" Height="0" LoadedData="customerDomainDataSource_LoadedData" Name="customerDomainDataSource" QueryName="GetCustomersQuery" Width="0">
<riaControls:DomainDataSource.DomainContext>
<my:DomainService1 />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
</Grid>
</UserControl>
Комментариев нет:
Отправить комментарий