понедельник, 30 августа 2010 г.

Модальное Prompt окно в Silverlight 4

Пусть перед нами стоит следующая задача:

При выполнении некоторого действия с данными пользователь должен ввести комментарий, почему он выполнил данное действие. Комментарий должен быть сохранен в базе данных с указанием текущего пользователя. Разумно хранить также саму информацию о действии, но в рамках данного примера нам дотаточно хранить лишь комментарий.

Таблицу можно создать, например, следующим скриптом:

USE [MyApplication]

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE TABLE [dbo].[Comments](

[ID] [int] IDENTITY(1,1) NOT NULL,

[User] [nvarchar](max) NOT NULL,

[Comment] [nvarchar](max) NOT NULL,

[Date] [datetime] NOT NULL,

CONSTRAINT [PK_Comments] PRIMARY KEY CLUSTERED

(

[ID] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]

GO

ALTER TABLE [dbo].[ Comments] ADD CONSTRAINT [DF_Comments_Date] DEFAULT (getdate()) FOR [Date]

GO

Также не забудем добавить следующие методы в доменный сервис:

public IQueryable<Comment> GetComments()

{

return this.ObjectContext.Comments;

}

public void InsertComment(Comment Comment)

{

if ((Comment.EntityState != EntityState.Detached))

{

this.ObjectContext.ObjectStateManager.ChangeObjectState(Comment, EntityState.Added);

}

else

{

this.ObjectContext.Comments.AddObject(Comment);

}

}

public void UpdateComment(Comment Comment)

{

this.ObjectContext.Comments.AttachAsModified(Comment, this.ChangeSet.GetOriginal(Comment));

}

public void DeleteComment(Comment Comment)

{

if ((Comment.EntityState == EntityState.Detached))

{

this.ObjectContext.Comments.Attach(Comment);

}

this.ObjectContext.Comments.DeleteObject(Comment);

}

Теперь при нажатии на некоторую кнопку мы будем просить у пользователя ввести комментарий, можно сделать это следующим образом:

private void btn_Click(object sender, RoutedEventArgs e)

{

var text = HtmlPage.Window.Prompt("Enter comment");

var comment = new Comment()

{

Comment = text,

Date = DateTime.Now,

User = WebContext.Current.Authentication.User.Identity.Name

};

var ctx = Context as MyApplicationDomainContext;

ctx. Comments.Add(comment);

}

Стандартный элемент Prompt является крайне простым в использовании, однако он не дает достаточной свободы. Например, нельзя создать многострочное поле для ввода комментария.

Таким образом, нам снова нужно разрабатывать свой контрол для ввода комментария.

Новый контрол должен обладать следующей функциональностью:

1. Окно должно быть модальным.

2. Окно должно содержать кнопки Ok и Cancel. Чтобы пользователь имел возможность отказаться от своих изменений.

3. Окно должно содержать многосторное поле для ввода комментария.

Создадим новый элемент, который нужно отнаследовать от ChildWindow. Разместим на нем текстовое поле:

<TextBox Name="txtComment"/>

Для того, чтобы текстовое поле стало многострочным нужно задать для него свойства TextWrapping, VerticalScrollBarVisibility и AcceptsReturn.

<TextBox Name="txtComment" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" AcceptsReturn="True"/>

Код страницы будет выглядеть так:

CommentPrompt.xaml

<controls:ChildWindow x:Class="MyApplication.Views.CommentPrompt"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"

Width="400" Height="300"

Title="Type comment">

<Grid x:Name="LayoutRoot" Margin="2">

<Grid.RowDefinitions>

<RowDefinition />

<RowDefinition Height="Auto" />

</Grid.RowDefinitions>

<TextBox Name="txtComment" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" AcceptsReturn="True"/>

<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />

<Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />

</Grid>

</controls:ChildWindow>

CommentPrompt.xaml.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

namespace MyApplication.Views

{

public partial class CommentPrompt : ChildWindow

{

public string Text

{

get

{

return txtComment.Text;

}

set

{

txtComment.Text = value;

}

}

public CommentPrompt()

{

InitializeComponent();

}

private void OKButton_Click(object sender, RoutedEventArgs e)

{

this.DialogResult = true;

}

private void CancelButton_Click(object sender, RoutedEventArgs e)

{

this.DialogResult = false;

}

}

}

Теперь мы можем использовать наше новое окно для ввода комментариев. Элемент ChildWindow не является модельным окном в том смысле, что он не блокирует поток выполнения программы, так что нам придется обрабатывать событие закрытия окна в своем коде следущим образом:

private void btn_Click(object sender, RoutedEventArgs e)

{

CommentPrompt prompt = new CommentPrompt();

prompt.Show();

prompt.Closed += (se, ev) =>

{

};

}

Можно также узнать какую кнопку нажал пользователь в форме, для этого нужно воспользоваться свойством DialogResult.

if (prompt.DialogResult.HasValue && prompt.DialogResult.Value == true)

{

}

Весь код обработчика:

private void btn_Click(object sender, RoutedEventArgs e)

{

CommentPrompt prompt = new CommentPrompt();

prompt.Show();

prompt.Closed += (se, ev) =>

{

if (prompt.DialogResult.HasValue && prompt.DialogResult.Value == true)

{

var comment = new Comment()

{

Comment = prompt.Text,

Date = DateTime.Now,

User = WebContext.Current.Authentication.User.Identity.Name

};

var ctx = Context as MyApplicationDomainContext;

ctx.Comments.Add(comment);

}

};

}

Код основной формы с данными и новой кнопкой:

<fw:FloatableWindow x:Class="MyApplication.Views.LoanView"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"

xmlns:fw="clr-namespace:System.Windows.Controls;assembly=FloatableWindow"

xmlns:df="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"

Width="650" Height="600"

Title="Loan Edit" xmlns:my="clr-namespace:MyApplication.Controls" Loaded="ChildWindow_Loaded" mc:Ignorable="d"

xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices"

xmlns:my1="clr-namespace:MyApplication.Web.Services"

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

xmlns:my2="clr-namespace:MyApplication.BLL"

xmlns:converter="clr-namespace:MyApplication"

xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"

HorizontalAlignment="Left" VerticalAlignment="Top">

<fw:FloatableWindow.Resources>

<converter:NullStringConverter x:Key="NullValueConverter" />

</fw:FloatableWindow.Resources>

<Grid x:Name="LayoutRoot">

<ScrollViewer>

<StackPanel>

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">

<TextBlock Text="Quarter" Margin="0,0,10,0"/>

<ComboBox Width="120" HorizontalAlignment="Right" Name="cbQuarter" SelectionChanged="cbQuarter_SelectionChanged"/>

</StackPanel>

<sdk:TabControl Name="tabControl">

<sdk:TabItem Header="Main">

<StackPanel>

<StackPanel Orientation="Horizontal" Margin="10,10,10,10">

<TextBlock Text="Status:" Margin="10,0,10,0" VerticalAlignment="Center"/>

<TextBlock Name="txtStatus" Margin="0,0,10,0" VerticalAlignment="Center"/>

</StackPanel>

<Grid Margin="10,10,10,10">

<riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my2:Rule, CreateList=true}" Height="0" Name="violationsDomainDataSource" QueryName="GetViolationsForLoan" Width="0" LoadedData="violationsDomainDataSource_LoadedData">

<riaControls:DomainDataSource.QueryParameters>

<riaControls:Parameter ParameterName="loanID" />

</riaControls:DomainDataSource.QueryParameters>

<riaControls:DomainDataSource.DomainContext>

<my1:MyApplicationDomainContext />

</riaControls:DomainDataSource.DomainContext>

</riaControls:DomainDataSource>

<ListBox ItemsSource="{Binding ElementName=violationsDomainDataSource, Path=Data}" DisplayMemberPath="Name" Background="LightPink" IsEnabled="False" SelectedIndex="-1" SelectionMode="Multiple" BorderBrush="{x:Null}">

</ListBox>

</Grid>

<StackPanel Orientation="Horizontal" Margin="10,10,10,10">

<my:BusyIndicator x:Name="biStatus">

<StackPanel Orientation="Vertical">

<Button Content="Enter comment" Width="140" Height="23" Margin="0,0,0,10" Name="btn" Click="btn_Click"/>

</StackPanel>

</my:BusyIndicator>

</StackPanel>

<my:CustomDataForm HorizontalAlignment="Center" x:Name="customDataForm1"

VerticalAlignment="Top" Width="450"

AutoEdit="True" AutoCommit="False"

AutoGenerateFields="True"

AutoGeneratingField="customDataForm1_AutoGeneratingField" Style="{StaticResource DataFormWithGroups}"

EditEnded="customDataForm1_EditEnded"

>

</my:CustomDataForm>

</StackPanel>

</sdk:TabItem>

</sdk:TabControl>

</StackPanel>

</ScrollViewer>

</Grid>

</fw:FloatableWindow>

Комментариев нет:

Отправить комментарий