![]() |
Platforms, Frameworks & Libraries »
Windows Presentation Foundation »
General
Intermediate
License: The Code Project Open License (CPOL)
Building a Personal Diary with WPFBy Nicko Satria UtamaAn article on how to build a personal diary with WPF. |
C#, XML, Windows, ASP.NET, XAML, WPF, VS2008, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||
Some people like to write down any event that occurs like their birthday or parties. They record the event from the recording device and save it everywhere so it can easily get lost. This little software just helps to organize the event and organize the video.
Windows Presentation Foundation (WPF) is a new technology from Microsoft that allows the developer to manipulate the user interface more easily. The developer can act as a designer to build a user interface in a more interactive manner.
Until today, WPF does not have a property or method that handles stream data like MediaElement. MediaElement uses property Source to grab the media or streaming media; it cannot grab from byte[] or Stream. It is not nice since it can come from many difference sources.
There are three files that need to be downloaded:
The source code of Personal Diary WPF is the main application. It can be opened using Visual C# 2008 Express Edition.
The source code of ASP.NET as video stream is the ASP.NET that can only produce the media streaming. For now I only produce Windows Video (*.wmv) and MPEG video (*.mpg). It can be opened using Visual Web Developer 2008 Express Edition.
An SQL file can be opened using SQL Server Management Studio Express. My database name is persdiary. You can change it and don't forget to change the connection string in the app.config. Run the SQL so that the tables are ready to use.
Open both projects - WPF project and Web site. Since not all windows installation equips with IIS, I use a built-in web server that comes with the product. Run the website first to make sure the Web server up and running.
After the website runs and the browser shows the result, copy the address URL from the browser to the value in the appSetting and find the key of hostpath.
Since MediaElement control with Source property from WPF cannot receive byte[] or Stream, we can manipulate it using ASP.NET as a video stream. First ASP.NET will load the data from the database. The video itself saves in the varbinary data types in the mstvideo table.
if (Request.QueryString.Count > 0)
{
string videoid = Request.QueryString["vid"];
if (!string.IsNullOrEmpty(videoid))
{
bool loadFull = false;
string loadFullStr = Request.QueryString["loadfull"];
if (!string.IsNullOrEmpty(loadFullStr)) loadFull = Convert.ToBoolean(loadFullStr);
else
{
Response.Write("<h1>Full Load or not?</h1>");
}
byte[] result = ReadVideo(videoid, loadFull);
WriteVideoToPage(result);
}
else
{
Response.Write("<h1>Need Video ID</h1>");
}
}
else
{
Response.Write("<h1>Need Video ID</h1>");
}
This code will detect the query string and call the method to query data from the database and write the result to this page. There are only two query strings: vid and loadfull. Query string vid is a video id that is useful to load video data by video id from the table. Query string loadfull is a flag not to load the video fully; in this case I will load 1/8th of total bytes received from the table.
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandType = CommandType.Text;
StringBuilder sb = new StringBuilder();
sb.Append("SELECT ");
sb.Append("DATALENGTH(vdcontent) AS vdcontent_length, ");
sb.Append(" vdcontent,vdformat ");
sb.Append(" FROM mstvideo ");
sb.Append(" WHERE vdid=@vdid ");
command.CommandText = sb.ToString();
command.Parameters.Add("@vdid", SqlDbType.Char).Value = videoid;
using (SqlDataReader reader = command.ExecuteReader())
int startIdx = 0;
long retval = 0;
if (!reader.HasRows)
{
Response.Write("<h1> Don't have rows ! </h1>");
}
while (reader.Read())
{
if (string.Compare(reader.GetString(reader.GetOrdinal
("vdformat")),".wmv",true)==0)
Response.ContentType = "video/x-ms-wmv";
else if (string.Compare(reader.GetString
(reader.GetOrdinal("vdformat")),".mpg",true)==0)
Response.ContentType = "video/mpeg";
int buffersize = reader.GetInt32(reader.GetOrdinal("vdcontent_length"));
if (!loadFull)
buffersize /= 8;
movieContainer = new byte[buffersize];
retval =reader.GetBytes(reader.GetOrdinal("vdcontent"), startIdx,
movieContainer, 0, buffersize);
}
}
}
The code above queries the video from the table. The select statement DATALENGTH(vdcontent) measures the length of data that is stored in vdcontent. I use command.ExecuteReader() to execute the query. The result is the length of the video, the video itself and the video format. The video format is useful to choose the MIME type of the ASP.NET. For now, I only support WMV and MPG. Again if loadfull is false, then I set the buffersize smaller; in this case I only divide the size by 8.
Response.BufferOutput = true;
//Response.BinaryWrite(movieContents);
BinaryWriter binWriter = new BinaryWriter(Response.OutputStream);
binWriter.Write(videoData);
binWriter.Flush();
ASP.NET will render the video by writing the contents using System.IO.BinaryWriter. The ASPX file itself is empty.
RegistryKey regKey = Registry.CurrentUser;
regKey = regKey.OpenSubKey("Software");
regKey = regKey.OpenSubKey("Nicko");
if (regKey != null)
{
result = regKey.GetValue("ConnectionString").ToString();
}
I use the registry key to get the connection string. So you can change the connection string once in the WPF app.config.
This is the main application that is written in WPF. The application can add a diary event and the video. You can click the video in the list below to enlarge the video to the center. Don't forget to add a reference to XCeed datagrid for WPF to make this work.
First I add two new namespaces in MainWindow.xaml - The XCeed datagrid and local namespace:
xmlns:local="clr-namespace:Diary.WPF"
xmlns:xceed="clr-namespace:Xceed.Wpf.DataGrid;assembly=Xceed.Wpf.DataGrid"
I add the Xceed datagrid to the grid layout:
<xceed:DataGridControl HorizontalAlignment="Left" Margin="10,10,0,0"
x:Name="dgvEvents" VerticalAlignment="Top" Width="380"
MaxHeight="180" Height="180" SelectionMode="Single" AutoCreateColumns="False"
NavigationBehavior="RowOnly" TabIndex="0" ReadOnly="True"
Mouse.MouseUp="Datagrid_MouseUp" Keyboard.KeyUp="DataGrid_KeyUp">
<xceed:DataGridControl.Columns>
<xceed:Column FieldName="EvDate" VisiblePosition="0" Title="Date " Width="80" />
<xceed:Column FieldName="EvName" VisiblePosition="1" Title="Name" Width="80"
TextWrapping="Wrap"/>
<xceed:Column FieldName="EvStories" VisiblePosition="2" Title="Stories"
TextWrapping="Wrap" Width="190"/>
</xceed:DataGridControl.Columns>
</xceed:DataGridControl>
The grid will change the selected item when the mouse is clicked and keyboard is pressed up and down. It will trigger to refresh the video content.
private void Datagrid_MouseUp(object sender, MouseButtonEventArgs e)
{
RefreshContents();
}
....
private void DataGrid_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up || e.Key == Key.Down)
{
RefreshContents();
}
}
I add the buttons that have a function to add event and add video.
...
<Button Height="23" x:Name="btnAddEvent" Width="30"
Click="btnAddEvent_Click">Add</Button>
...
<Button x:Name="btnAddNewVideo" Click="btnAddNewVideo_Click">Add new</Button>
The button will trigger an event to open a dialog window.
private void btnAddEvent_Click(object sender, RoutedEventArgs e)
{
...
bool? result = dlgInsert.ShowDialog();
...
}
}
The method will open the new event dialog window:
private void btnAddNewVideo_Click(object sender, RoutedEventArgs e)
{
...
bool? result = dlgVideo.ShowDialog();
...
}
The method will open the new video dialog window:
When I click one of the videos below, the video will enlarge in the middle and play the video in full. When I click that large video, it will go back to the list below:
private void me_MouseUp(object sender, MouseButtonEventArgs e)
MediaElement me = sender as MediaElement;
if (stkpanVideo.Children.IndexOf(me) >= 0)
{
//Quick and Dirty
...
me.Height *= 4;
me.Width *= 4;
...
}
else
{
//Quick and Dirty
...
me.Height /= 4;
me.Width /= 4;
...
}
}
I create an XAML to act as a window dialog to add events to the table. It is Insert InsertEventDialog.xaml. I use a grid layout to create a table-like layout with textblocks and textboxes as input controls. I use a Windows Form DateTimePicker to choose event date. I create InsertNewVideo.xaml to add a video for the selected diary event.
...
...
<TextBlock .../>
<TextBox .../>
...
<WindowsFormsHost Name="wpfHost">
<windowsform:DateTimePicker ...</WindowsFormsHost>
I learnt how to bind data to the WPF control using the ObservableCollection <of T>, not only Dataset or Datatable. I just write the property name to the binding source in the control property and automatically bind.
ASP.NET can be used as a streaming video source, so I can use it as a dynamic source for MediaElement.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 12 Jan 2008 Editor: Deeksha Shenoy |
Copyright 2008 by Nicko Satria Utama Everything else Copyright © CodeProject, 1999-2009 Web13 | Advertise on the Code Project |