Modify And Save an EF EntityDataSource Bound Entity From Code Behind

If you're using databound controls (e.g. FormView) and binding them to an EntityDataSource you might want to be able to modify (and save) the underlying entity from code. For example, if you have a Question entity bound to a FormView via an EntityDataSource you might want a button to allow the use to vote up or down the question (like StackOverflow for example). To be able to do this without extra trips to the database, the first thing we need to do is get hold of the EF ObjectContext that the EntityDataSource is using.

        // Context that we can use for code-behind operations
        ObjectContext questionObjectContext = null;


        protected void QuestionEntityDataSource_ContextCreated(object sender, EntityDataSourceContextCreatedEventArgs e)
        {
            questionObjectContext = e.Context;
        }

When the QuestionEntityDataSource creates it's context, we take a reference to it in our private field questionObjectContext.

Now in the button click we can up-vote the question:

 

        protected void btnVoteUp_Click(object sender, EventArgs e)
        {
            // force a databind to ensure we have a DataItem in the FormView        
            FormView1.DataBind();

            // Get the actual entity represented by the FormView
            Question questionToUpdate = FormView1.DataItem.WrappedEntity<Question>();

            // Vote-up
            questionToUpdate.VoteScore++;
           
            // using our 'copy' of the EntityDataSource ObjectContext, save the changes
            questionObjectContext.SaveChanges(true);
           
            // Force rebind of FormView to ensure newest data displayed
            FormView1.DataBind();                     
        }

This method feels like a bit of a hack, but ideally you would provide a client-side AJAX version, only if JavaScript is disabled on the client do we use this server-side up-vote.

SHARE:

Accessing Entity Framework Entities In EntityDataSource Data-Bound Controls

If using ASP.NET EntityDataSource and databound controls you may need to access the actual entity object being represented in the control, e.g. a data row in a table or a single entity in a FormView. The actual entity is not readily available however as it is automatically wrapped in a System.Web.UI.WebControls.EntityDataSourceWrapper which is not accessible. The extension method below allows you to gain access to the strongly typed, underlying entity. It is based on the article by Diego Vega which explains the wrapping behaviour in more detail. 

 /// <summary>
/// Gets the actual EF entity object that is being wrapped and databound.
/// </summary>
/// <example>
/// Advert ad = myFormView.DataItem.WrappedEntity<Advert>();
/// (where myFormView is databound to EntityDataSource returning Advert entity)
/// </example>
static class WrappedEFEntityExtensions
{
    public static TEntity WrappedEntity<TEntity>(this object dataItem) where TEntity : class
    {
        var entity = dataItem as TEntity;

        if (entity != null)
            return entity;

        var typeDescriptor = dataItem as ICustomTypeDescriptor;

        if (typeDescriptor != null)
            return (TEntity)typeDescriptor.GetPropertyOwner(null);

        return null;
    }
}

SHARE:

Diagnosing WCF Problems Using SvcTraceViewer.exe

You can use Microsoft Service Trace Viewer (SvcTraceViewer.exe) to help diagnose problems with connections to your WCF services.

For example, if calling WCF service from the client using AJAX (or maybe AJAJ for JSON!) you might get a 500 Server Error, you set a breakpoint in you service but that is never hit, using SvcTraceViewer.exe you can attempt to get some more info.

Add the following to your app\web.config:

 <system.diagnostics>
  <sources>
    <source name="System.ServiceModel" switchValue="Verbose,ActivityTracing"
      propagateActivity="true">
      <listeners>
        <add type="System.Diagnostics.DefaultTraceListener" name="Default">
          <filter type="" />
        </add>
        <add name="ServiceModelTraceListener">
          <filter type="" />
        </add>
      </listeners>
    </source>
    <source name="System.ServiceModel.MessageLogging" switchValue="Verbose,ActivityTracing">
      <listeners>
        <add type="System.Diagnostics.DefaultTraceListener" name="Default">
          <filter type="" />
        </add>
        <add name="ServiceModelMessageLoggingListener">
          <filter type="" />
        </add>
      </listeners>
    </source>
  </sources>
  <sharedListeners>
    <add initializeData="MyWCFTraceLog.svclog"
      type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
      name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
      <filter type="" />
    </add>
    <add initializeData="MyWCFTraceLog.svclog"
      type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
      name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
      <filter type="" />
    </add>
  </sharedListeners>
  <trace autoflush="true" />
</system.diagnostics>

 

You can then launch SvcTraceViewer.exe from the Visual Studio command prompt, File-->Open and choose the log file (MyWCFTraceLog.svclog in the above config). You can supply a full path to the log file, e.g.:

 <add initializeData="c:\temp\MyWCFLogFiles\MyFooApp\MyWCFTraceLog.svclog"

 

SHARE:

Asp.net AJAX service proxy intellisense in external js

If you have service reference (e.g. to an AJAX Enabled WCF Service) in your ScriptManager (or ToolkitScriptManager):

<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
    <Services>
        <asp:ServiceReference Path="~/MotoService.svc" />
    </Services>
</asp:ToolkitScriptManager>

and your are using an external JavaScript file you can enable JavaScript intellisense by adding the following 2 lines to the top of your .js (replacing ~/MotoService.svc with the path to your own service):

/// <reference name="MicrosoftAjax.js" />
/// <reference path="~/MotoService.svc" />

 

SHARE:

JavaScript Breakpoints Not Working In Visual Studio 2008

This can happen, sometimes fixed by re-installing VS or installing VS 2008 SP1. In this case it seems Javascript breakpoints do not seem to work in Visual Studio 2008 when Silverlight debugging is enabled, if you un-check the Silverlight option in the debuggers section, the JavaScript breakpoint will now be hit. Not sure if it's by design or a bug...

 

SHARE:

Blendable Silverlight (and WPF) MVVM Applications With Dependency Injection

Introduction

One of the challenges with the idea of having separate developer and designers is how to allow the developers to write code while at the same time designers are working on the UI.

The goal is to give designers working in Expression Blend some sample data that they can data-bind to, that will match the runtime data items without requiring additional build scripts\etc.

The Model-View-ViewModel (MVVM) design pattern is a popular way to architect a SL\WPF app to provide separation of concerns, testability, etc. This article assumes a basic understanding of the MVVM pattern.

Getting Started - Defining The ViewModel

We create an interface to define out ViewModel (we can do this for every distinct view in the application). Before we do this though, we need something to represent our model data, for example a person:

     public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

Next we can define our ViewModel interface to allow the user to edit a person's details, the idea is that our view (our XAML user control) will be bound to a class that implements this interface. All data and operations are provided by the ViewModel, i.e. the view has no direct contact with the model.

     public interface IEditPersonDetailsViewModel
    {
        Person PersonToEdit { get; set; }
    }

It is this interface that allows both the designer and developer to work with a single common, well-defined set of data items.

Creating Some Design-Time Data

Now we have defined what data our view will have access to, we can proceed to provide the designer with some sample data to work with.

Remember that one of the goals for us to be able to run the application without having to modify configurations or have extra scripts, i.e. we want our app to provide a 'real' ViewModel at runtime, but a 'dummy' one to the designer in Blend. One way of providing this to to implement a version of the Service Locator design pattern:

    public class ViewModelServiceLocator
    {
        public IEditPersonDetailsViewModel GetEditPersonDetailsViewModel
        {
            get
            {
                return new EditPersonDetailsViewModel_DesignTime();
            }
        }
    }

The GetEditPersonDetailsViewModel property (by using a property we can bind to it in Blend) at the moment always returns an instance of  EditPersonDetailsViewModel_DesignTime, we will modify this shortly.EditPersonDetailsViewModel_DesignTime is defined as:

     public class EditPersonDetailsViewModel_DesignTime : IEditPersonDetailsViewModel
    {
        public EditPersonDetailsViewModel_DesignTime()
        {
            PersonToEdit = new Person()
            {
                Name="Mr Design Time Data",
                Age=44
            };
        }

        #region IEditPersonDetailsViewModel Members

        public Person PersonToEdit { get; set; }

        #endregion
    }

It is an instance of this class will provide the design time data in Blend.

Binding to Design-Time Data in Blend

(You can download a trial copy of blend from Microsoft.)

Open your project in blend and  on the Data tab choose "Define New Object Data Source...".

 

 

Select our ViewModelServiceLocator class and click OK.

 



Now we bind our usercontrol to an instance of ViewModelServiceLocator, you can do this by dragging from the data tab to [UserControl] in the Objects and Timeline pane:

 

If you look at the xaml this creates, it's basically setting the DataContext of the entire user control to the return value of the GetEditPersonDetailsViewModel property.


Now the designer can (for example) bind a textbox to the person name:



So now we have a design time ViewModel bound in Blend. If we run the app now, we would get the design time ViewModel at runtime, so the next step is to provide a 'real' ViewModel at runtime.

Providing a Runtime ViewModel

First we define our ViewModel to be used at runtime (with a hard-coded person for illustration purposes):

    public class EditPersonDetailsViewModel : IEditPersonDetailsViewModel
    {
        public EditPersonDetailsViewModel()
        {
            PersonToEdit = new Person()
            {
                Name="Mr Runtime Data",
                Age=22
            };
        }

        #region IEditPersonDetailsViewModel Members

        public Person PersonToEdit{ get; set;}

        #endregion
    }

We can then modify our ViewModel service locator to provide our runtime version:

    public class ViewModelServiceLocator
    {
        public IEditPersonDetailsViewModel GetEditPersonDetailsViewModel
        {
            get
            {
                if (System.ComponentModel.DesignerProperties.IsInDesignTool)
                    return new EditPersonDetailsViewModel_DesignTime();
                else
                    return new EditPersonDetailsViewModel();
            }
        }
    }

When we run the app we get our runtime version: 



In a real situation you could pass in the Person to be editied to the runtime viewmodel constructor and possibly use Dependency Injection to provide the dependency.

Adding Dependency Injection to the Service Locator

We can add another layer of abstraction by having the service locator delegate to a DI framework. The examples below are from another project which uses Ninject to provide DI.

    public class ViewModelServiceLocator
    {
        public IMainViewModel GetMainViewModel
        {
            get
            {
                return KernelHost.Kernel.Get<IMainViewModel>();
            }
        }



        public IAddNewWeightViewModel GetAddNewWeightViewModel
        {
            get
            {
                return KernelHost.Kernel.Get<IAddNewWeightViewModel>();
            }
        }



        public IPersonDetailsViewModel GetPersonDetailsViewModel
        {
            get
            {
                return KernelHost.Kernel.Get<IPersonDetailsViewModel>();
            }
        }
    }

 

 

    public static class KernelHost
    {
        static IKernel _kernel;
       

        static KernelHost ()
        {
            _kernel = new StandardKernel(new DI.StandardNInjectModule());
        }


        public static IKernel Kernel
        {
            get
            {             
                return _kernel;
            }
            set
            {
                _kernel = value;
            }
        }
    }

 

    public class StandardNInjectModule : StandardModule
    {
        public override void Load()
        {           
            // For normally injected IModel resolve using the instance provided by factory
            Bind<IModel>().ToFactoryMethod<IModel>(ModelFactory.Get);

            // For when a new IModel is required (and explicitly not required from thefactory)
            Bind<IModel>().To<Model>().Only(When.Context.Variable("createNewNotFromFactory").EqualTo(true));

            Bind<IModelStore>().To<IsolatedStorageModelStore>();
            Bind<IModelLoader>().To<ModelLoader>();


           
            Bind<IPerson>().To<Person>().WithArgument<string>("name", "No Name Specified").WithArgument<double>("heightCm",150);
            Bind<IBMICalculator>().To<BMICalculator>().Using<SingletonBehavior>();
            Bind<IWeightRecord>().To<WeightRecord>();
            Bind<IAggregateData>().To<AggregateData>();



            // Bind view models
            Bind<IMainViewModel>().To<MainViewModel>();
            Bind<IAddNewWeightViewModel>().To<AddNewWeightViewModel>();
            Bind<IPersonDetailsViewModel>().To<PersonDetailsViewModel>();
         

#region "Blend design time view models"
#if DEBUG
            Bind<IMainViewModel>().To<MainViewModelDesignTime>().OnlyIf(x => (System.ComponentModel.DesignerProperties.IsInDesignTool));
            Bind<IAddNewWeightViewModel>().To<AddNewWeightViewModelDesignTime>().OnlyIf(x => (System.ComponentModel.DesignerProperties.IsInDesignTool));
            Bind<IPersonDetailsViewModel>().To<PersonDetailsViewModelDesignTime>().OnlyIf(x => (System.ComponentModel.DesignerProperties.IsInDesignTool));
           
#endif
#endregion
        }
    }

 

SHARE:

Ensure Your Silverlight App Has Focus When The Page Loads

Assuming that your SL app is running in-browser, you may want your SL app to have initial focus, e.g. when it loads a splash screen, the OK button has focus.

You can help achieve this by using System.Windows.Browser.HtmlPage.Plugin.Focus(); in your loaded event handler for your usercontrol\childwindow, e.g.:

 

        private void ChildWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // ensure SL plugin has focus
            System.Windows.Browser.HtmlPage.Plugin.Focus();
        }

SHARE:

Silverlight & WPF - Binding to a specific item in a collection

If you have a collection of items (for example a list of strings) that is assigned to the DataContext of a given XAML element (or parent element) you can use standard array index notation to get at a specific item in the list, just use Path=[n] where n is the item index.

For example:

<TextBlock Name="exampleBindingText" Text="{Binding Path=[3]}" />

With a DataContext set using the code:

            List<string> months = new List<string>()
            {
                "Jan", // 1st element in collection at index 0
                "Feb", // 2nd element in collection at index 1
                "Mar", // 3rd element in collection at index 2
                "Apr"  // 4th element in collection at index 3
            };

            exampleBindingText.DataContext = months;

Would result in the Text of the TextBlock outputting "Apr" as Path=[3] will get the 4th element in the collection.

SHARE:

Silverlight Open and Save Dialog Boxes

If you want your Silverlight app to be able to load and save data to the users file system in a location of their choice (such as My Documents, Desktop, etc.) you can use the SaveFileDialog and OpenFileDialog. This is different from reading and writing to Isolated Storage as it requires the user to interact with a dialog box, choose filename, etc. The user can also cancel out of the dialog box, which returns a value of false from the ShowDialog() method.

Below is a simple example of saving a hard-coded string "Test string to save." to a file as chosen by the user. In a live application you would want to think more carefully about possible problems arising from loading and saving, e.g. what if user loads a corrupt file, or a binary file where a text file was expected, etc. Also with the loading of files you should evaluate the security risks of allowing arbitrary data to be loaded into your application.

 

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = "Text Files (*.txt)|*.txt";
            dlg.DefaultExt = "*.txt";

            // if the user doesn't cancel           
            if (dlg.ShowDialog() == true)
            {
                try
                {
                    // create a StreamWriter over the base stream returned by SaveFileDialog's OpenFile() method
                    using (StreamWriter writer = new StreamWriter(dlg.OpenFile()))
                    {
                        writer.Write("Test string to save.");
                        writer.Close();
                    }
                }
                catch (Exception ex) // catch all, ideally you should catch specific exceptions in most-specific to general
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }



        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "Text Files (*.txt)|*.txt";

            // if the user doesn't cancel
            if (dlg.ShowDialog() == true)
            {
                try
                {
                    string loadedText;
                    // create a StreamReader from OpenFileDialog's OpenText() method
                    using (StreamReader reader = dlg.File.OpenText())
                    {
                        loadedText = reader.ReadToEnd();
                        reader.Close();
                    }
                    MessageBox.Show(loadedText);
                }
                catch (Exception ex) // catch all, ideally you should catch specific exceptions in most-specific to general
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }
 

SHARE: