Today I was preparing a demo app which integrates WPF and LinqToSql. The idea is to implement the same pattern I've always used with NHibernate: a Session DataContext per Window, automatically disposed when its owner is closed and shared among all the various UserControls it has.
So, what I did was building my custom window class with an amazing MyDatabaseDataContext property in it
10 public class PersistentWindow : Window
11 {
12 private MyDatabaseDataContext myDatabaseDataContext =
13 new MyDatabaseDataContext();
14 public MyDatabaseDataContext MyDatabaseDataContext
15 {
16 get { return myDatabaseDataContext; }
17 set { myDatabaseDataContext = value; }
18 }
19 }
Now, every window in my application can access the built in LINQ DataContext simply inheriting from my PersistentWindow custom class:
1 <classes:PersistentWindow x:Class="MySampleApp.MainWindow"
2 xmlns="http://...."
3 xmlns:x="http://...."
4 xmlns:classes="clr-namespace:MySampleApp.Classes"
5 Title="Demo Application" Height="450" Width="600">
Pretty easy, isn't it? But often I do love holding a lot of logic and layout inside UserControls, both to keep my home window code simple and to build re-utilizable blocks; and almost always those UserControl need some DataBase access, that's why I need to share PersistentWindow's DataContext among all the UserControls.
If I was in Windows Forms, I probably would have ended shadowing the FindForm method with something like this:
9 public PersistentForm FindForm()
10 {
11 return base.FindForm() as PersistentForm;
12 }
But WPF has that fantastic DependencyProperty infrastructure, so maybe could be more elegant to leverage its Value Inheritance to achieve our goal. In fact, value inheritance allows property value inheritance across controls logical tree. That means that, if both your parent (window) control and your some-level child (UserControl) have the same property, the parent's property value is forwarded to every child unless they don't redefine their own value.
What we need to do is rewriting our MyDatabaseDataContext property as an AttachedProperty:
13 public static readonly DependencyProperty MyDatabaseDataContextProperty =
14 DependencyProperty.RegisterAttached("MyDatabaseDataContext",
15 typeof(MyDatabaseDataContext), typeof(PersistentWindow),
16 new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
17 public static void SetMyDatabaseDataContext(
18 UIElement instance, MyDatabaseDataContext value)
19 {
20 instance.SetValue(MyDatabaseDataContextProperty, value);
21 }
22 public static MyDatabaseDataContext GetMyDatabaseDataContext(UIElement instance)
23 {
24 return instance.GetValue(
25 MyDatabaseDataContextProperty) as MyDatabaseDataContext;
26 }
Did you notice that Inherits flag? It's what does all the magic! In fact, having a reference to window's Linq Context from our custom UserControl is simply a matter of writing a property like this:
11 public class PersistentUserControl : UserControl
12 {
13 public MyDatabaseDataContext MyDatabaseDataContext
14 {
15 get
16 {
17 return this.GetValue(
18 PersistentWindow.MyDatabaseDataContextProperty)
19 as MyDatabaseDataContext;
20 }
21 set
22 {
23 this.SetValue(PersistentWindow.MyDatabaseDataContextProperty, value);
24 }
25 }
26 }
Nice, isn't it?
