One of the core concepts for WPF development was the separation of Design from Development. This means you might want to open up the XamDataPresenter inside of Blend and style it in order to fully achieve the experience that you wish to deliver. Now, you could do all of the work on a 'dummy' control inside of Blend and cut-copy-paste the XAML code into your Windows Forms project, but that isn't really a good scenario and breaks down the communication between the two tooling environments and if I want to fully utilize the power of WPF styling capabilities then I should look for another approach.
One way to get around the problem that I've mentioned is to create a WPF Control Library that hosts the XamDataPresenter. This will enable me to fully design the control inside of Blend and I will be able to host the ControlLibrary as the control inside of ElementHost within Visual Studio. (Note: Control Libraries can be built in Blend, but unless you add them to a dummy project they cannot be tested/run.)
The first challenge I will face is that there is no assigned data source; to get around this I can create a simple XML file that mimics my datasource and I can use that as an intermediate step to style my XamDataPresenter or I can set the BindToSampleData property which will fill my XamDataPresenter with a generic set of data and enable me to focus purely on the styling aspects of the control. That being said, I now have all of the abilities as a designer like the ability to visually style the control and add custom presenters.
After making all of the design changes, I can simply build my project and either a.) add the project to my Windows Forms Solution or b.) add the DLL for my custom control to the references in the Windows Forms Project.
Inside of Visual Studio, I associate the UserControl to the element host by following the same process as previously noted. I will notice that there is no DataSource property, and in fact, none of the familiar properties that I had in my first sample are there. As a matter of fact, I am now seeing all of the properties of the UserControl and not that of the XamDataPresenter. The ideal solution is to have both the ability to design in Blend and code inside of Visual Studio. To achieve this, I'll have to add some code to my UserControl that exposes the underlying properties of the XamDataPresenter.
To begin, I'll start by adding a public property to my UserControl that lets me access the datasource property of the XamDataPresenter. The code might look something like this:
public System.Collections.IEnumerable DataSource { get { return this.XamDataPresenterInternal.DataSource; } set { this.XamDataPresenterInternal.DataSource = value; } }
public System.Collections.IEnumerable DataSource
{
get { return this.XamDataPresenterInternal.DataSource; } set { this.XamDataPresenterInternal.DataSource = value; }
get { return this.XamDataPresenterInternal.DataSource; }
set { this.XamDataPresenterInternal.DataSource = value; }
}
Theoretically, I can expose all of the properties I need on the underlying XamDataPresenter by associating them as public properties of the usercontrol. Aside from properties, I may also need to expose some events to my base project. In this sample, I'll add some events that validate cell values before exiting edit mode on a grid cell. Since, the EditModeEndingEvent will not be available in my Windows Forms Application, I'll create a public event off of the user control that will handle the event off of the underlying XamDataPresenter and let me act on it inside of my Windows Forms Application. The following code will be placed in my .xaml.cs file:
public static RoutedEvent EditModeEndingEvent = EventManager.RegisterRoutedEvent ("EditModeEnding", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(XamDataPresenterWrapper)); public event RoutedEventHandler EditModeEnding { add { AddHandler(EditModeEndingEvent, value); } remove { RemoveHandler(EditModeEndingEvent, value); } } void XamDataPresenterInternal_EditModeEnding(object sender, Infragistics.Windows.DataPresenter.Events.EditModeEndingEventArgs e) { RaiseEvent(new RoutedEventArgs(XamDataPresenterWrapper.EditModeEndingEvent, e)); }
public static RoutedEvent EditModeEndingEvent = EventManager.RegisterRoutedEvent
("EditModeEnding", RoutingStrategy.Bubble, typeof(RoutedEventHandler),
typeof(XamDataPresenterWrapper));
public event RoutedEventHandler EditModeEnding
add { AddHandler(EditModeEndingEvent, value); } remove { RemoveHandler(EditModeEndingEvent, value); }
add { AddHandler(EditModeEndingEvent, value); }
remove { RemoveHandler(EditModeEndingEvent, value); }
void XamDataPresenterInternal_EditModeEnding(object sender,
Infragistics.Windows.DataPresenter.Events.EditModeEndingEventArgs e)
RaiseEvent(new RoutedEventArgs(XamDataPresenterWrapper.EditModeEndingEvent, e));
RaiseEvent(new
RoutedEventArgs(XamDataPresenterWrapper.EditModeEndingEvent, e));
Also, make sure that the .xaml file knows of the event:
<igDP:XamDataPresenter Name="XamDataPresenterInternal" EditModeEnding="XamDataPresenterInternal_EditModeEnding"/>
<igDP:XamDataPresenter Name="XamDataPresenterInternal"
EditModeEnding="XamDataPresenterInternal_EditModeEnding"/>
Now that I've handled these changes to my ControlLibrary, I'm going to build it and then jump back into my Windows Forms Project and start hooking everything up. To begin, I'll start by hooking up the DataSource Property:
…
using System.Windows.Forms.Integration;
namespace WindowsForms_WPF_InteropDemo
public partial class Main: Form { private ElementHost XamHost; private Infragistics.XamDataPresenterWrapper XamDataPresenter; … private void Main_Load(object sender, EventArgs e) { … XamHost = new ElementHost(); XamHost.Dock = DockStyle.Fill; this.Controls.Add(XamHost); XamDataPresenter = new Infragistics.XamDataPresenterWrapper(); XamDataPresenter.DataSource = this.vSalesPersonSalesByFiscalYearsBindingSource; XamHost.Child = XamDataPresenter; } …
public partial class Main: Form
private ElementHost XamHost; private Infragistics.XamDataPresenterWrapper XamDataPresenter; … private void Main_Load(object sender, EventArgs e) { … XamHost = new ElementHost(); XamHost.Dock = DockStyle.Fill; this.Controls.Add(XamHost); XamDataPresenter = new Infragistics.XamDataPresenterWrapper(); XamDataPresenter.DataSource = this.vSalesPersonSalesByFiscalYearsBindingSource; XamHost.Child = XamDataPresenter; }
private ElementHost XamHost;
private Infragistics.XamDataPresenterWrapper XamDataPresenter;
private void Main_Load(object sender, EventArgs e)
… XamHost = new ElementHost(); XamHost.Dock = DockStyle.Fill; this.Controls.Add(XamHost); XamDataPresenter = new Infragistics.XamDataPresenterWrapper(); XamDataPresenter.DataSource = this.vSalesPersonSalesByFiscalYearsBindingSource; XamHost.Child = XamDataPresenter;
XamHost = new ElementHost();
XamHost.Dock = DockStyle.Fill;
this.Controls.Add(XamHost);
XamDataPresenter = new Infragistics.XamDataPresenterWrapper();
XamDataPresenter.DataSource =
this.vSalesPersonSalesByFiscalYearsBindingSource;
XamHost.Child = XamDataPresenter;
After completing this work item, I can hook up the event and perform any logic in that event that I need to handle. For the purpose of this sample, I'll add the event handler to the (Main_Load) Form_Load event and then I'll add the code to perform whatever logic is needed.
using Infragistics.Windows.DataPresenter.Events;
… XamDataPresenter.EditModeEnding += new System.Windows.RoutedEventHandler(XamDataPresenter_EditModeEnding); … void XamDataPresenter_EditModeEnding(object sender, System.Windows.RoutedEventArgs e) { // Arguments for the Edit Mode Ending Event EditModeEndingEventArgs editEndingArgs = e.OriginalSource as EditModeEndingEventArgs; if (editEndingArgs == null) return; // Column name of the field being edited (Infragistics.Windows.DataPresenter.Events) string columnName = editEndingArgs.Cell.Field.Name; // Value of the edited Cell (after edits were made) string newCellValue = editEndingArgs.Editor.Text; if (columnName == "Title" ) { // Check the New Cell Value to see if it changed to anything other // than Sales Representative if (newCellValue != "Sales Representative") { //Do not persist the changes editEndingArgs.AcceptChanges = false; MessageBox.Show("Title Must Be Sales Representative"); } } }
XamDataPresenter.EditModeEnding +=
new System.Windows.RoutedEventHandler(XamDataPresenter_EditModeEnding);
void XamDataPresenter_EditModeEnding(object sender, System.Windows.RoutedEventArgs e)
// Arguments for the Edit Mode Ending Event EditModeEndingEventArgs editEndingArgs = e.OriginalSource as EditModeEndingEventArgs; if (editEndingArgs == null) return; // Column name of the field being edited (Infragistics.Windows.DataPresenter.Events) string columnName = editEndingArgs.Cell.Field.Name; // Value of the edited Cell (after edits were made) string newCellValue = editEndingArgs.Editor.Text; if (columnName == "Title" ) { // Check the New Cell Value to see if it changed to anything other // than Sales Representative if (newCellValue != "Sales Representative") { //Do not persist the changes editEndingArgs.AcceptChanges = false; MessageBox.Show("Title Must Be Sales Representative"); } }
// Arguments for the Edit Mode Ending Event
EditModeEndingEventArgs editEndingArgs = e.OriginalSource as
EditModeEndingEventArgs;
if (editEndingArgs == null)
return;
// Column name of the field being edited (Infragistics.Windows.DataPresenter.Events)
string columnName = editEndingArgs.Cell.Field.Name;
// Value of the edited Cell (after edits were made)
string newCellValue = editEndingArgs.Editor.Text;
if (columnName == "Title" )
// Check the New Cell Value to see if it changed to anything other // than Sales Representative if (newCellValue != "Sales Representative") { //Do not persist the changes editEndingArgs.AcceptChanges = false; MessageBox.Show("Title Must Be Sales Representative"); }
// Check the New Cell Value to see if it changed to anything other
// than Sales Representative
if (newCellValue != "Sales Representative")
//Do not persist the changes editEndingArgs.AcceptChanges = false; MessageBox.Show("Title Must Be Sales Representative");
//Do not persist the changes
editEndingArgs.AcceptChanges = false;
MessageBox.Show("Title Must Be Sales Representative");
In this case, making sure that all of the "Sales Representatives" remain "Sales Representatives" was my task. After having done this work, why not take a look at the final result on the next page?