Code behind WPF and F# - wpf

Is it possible to make an application in F# that uses WPF with a classic code behind? I know it works perfect with MVVM and no code behind, but I need to implement an interface on a UserControl. Is that possible with F#?
To help a bit, here is the code I want to translate from C# to F#
public class Test : UserControl, IContent {
public void InitializeComponents() {
// Do the initialization magic
}
public Test() {
}
public void OnFragmentNavigation(FragmentNavigationEventArgs e) {
this.DataContext = new { description = "Hallo Welt :)" };
}
public void OnNavigatedFrom(NavigationEventArgs e) {
}
public void OnNavigatedTo(NavigationEventArgs e){
}
public void OnNavigatingFrom(NavigatingCancelEventArgs e) {
}
}
And this is the markup
<UserControl xmlns="http://schemas.microsoft.com/netfx/2007/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Test">
<TextBlock Text="{Binding description}"></TextBlock>
</UserControl>

It really depends on what you mean by "classic code behind". As mentioned by Petr, F# does not have partial classes (and there is also no editor support), so you won't get the same experience (when you are accessing elements or adding events). But you can certainly build a WPF application that uses the same programming model.
One way to get something that is very close to standard code behind is to define a class, associated with each xaml file, that looks something like this:
type SomeComponent() =
let uri = System.Uri("/AppName;component/SomeComponent.xaml", UriKind.Relative)
let ctl = Application.LoadComponent(uri) :?> UserControl
let (?) (this : Control) (prop : string) : 'T =
this.FindName(prop) :?> 'T
let okBtn : Button = ctl?OkButton
do okBtn.Click.Add(fun _ -> (* .. whatever *) )
This loads the XAML content and then uses the dynamic lookup operator to find all the UI elements (which you'd get for free in C#). A nicer F# solution is to use FsXaml, which has a XAML type provider (but sadly, not much documentation).

I found a solution, I just make it short, here is the code:
namespace Testns
open System.Windows.Controls
open FirstFloor.ModernUI.Windows
open Microsoft.FSharp.Core
open System
type TestUserControl() =
inherit UserControl()
interface IContent with
member x.OnFragmentNavigation(e: Navigation.FragmentNavigationEventArgs): unit =
let vm = ViewModel("Hallo Welt :)")
base.DataContext <- vm
()
member x.OnNavigatedFrom(e: Navigation.NavigationEventArgs): unit = ()
member x.OnNavigatedTo(e: Navigation.NavigationEventArgs): unit = ()
member x.OnNavigatingFrom(e: Navigation.NavigatingCancelEventArgs): unit = ()
And the markup
<local:TestUserControl xmlns="http://schemas.microsoft.com/netfx/2007/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Testns;assembly=App">
<TextBlock Text="{Binding description}"></TextBlock>
</local:TestUserControl>
This is not the answer for the actual question, it just works for my use case. So feel free to answer it :)

Probably no. As far as I know F# doesn't support partial classes.
But you can use F# XAML type provider as described here: http://www.mindscapehq.com/blog/index.php/2012/04/29/using-wpf-elements-from-f/

Related

How to use ResourceDictionaries in different assemblies and DesignTime support in VS2010

i have the following problem. i have ResourceDictionaries located in different assemblies. if i create UserControls and use Styles and Resourcen from this ResourceDictionaries all works fine on runtime, but at designtime i got errors in vs2010 like - Resource with name "InvertConverter" could not be located.
CoreResource.dll
OtherResource.dll
UserControl.dll (reference the both above)
OtherWpf.dll (reference all above and use the usercontrols)
Now i checked a lot of post and blogs these days related to this problem. one solution was to add the ResourceDictionaries to every UserControl - this would work but create a lot of overhead at runtime. all other solutions i find did not work for me.
i will post what i have done at leat as an answer because it works for me. but i'd like to see other/better soltutions.
here is what i did now.
i simply use a static method to add my resourcedictionaries just at designtime.
public class DesignTimeResourceLoader
{
public static void LoadResources4DesignTime(UserControl ctrl)
{
//do this just in DesignMode
if (Convert.ToBoolean(DesignerProperties.IsInDesignModeProperty.GetMetadata(ctrl).DefaultValue))
{
var uricore = new Uri("/CoreResource;component/ResourceDictionary.xaml", UriKind.Relative);
var core = (ResourceDictionary)Application.LoadComponent(uricore);
ctrl.Resources.MergedDictionaries.Add(core);
var uriother = new Uri("/OtherResource;component/OtherResourceDictionary.xaml", UriKind.Relative);
var other = (ResourceDictionary)Application.LoadComponent(uriother);
ctrl.Resources.MergedDictionaries.Add(other);
//if you have(need more just add here
}
}
}
i create and use this class in my UserControl.dll and for every Usercontrol i call the method in the constructor.
public partial class MyControl : UserControl
{
public MyControl ()
{
DesignTimeResourceLoader.LoadResources4DesignTime(this);
InitializeComponent();
}
}
this works for me atm. bu maybe there are some drawback i did not see now.

Can I implement my own view resolution service and have RequestNavigate use it?

I 'm fairly new to Prism and I 'm currently re-writing one of our existing applications using Prism as a proof of concept project.
The application uses MVVM with a ViewModel first approach: our ViewModel is resolved by the container, and an IViewResolver service figures out what view it should be wired up to (using name conventions amongst other things).
The code (to add a view to a tab control) at the moment looks something like this:
var vm = (get ViewModel from somewhere)
IRegion reg = _regionManager.Regions["MainRegion"];
var vw = _viewResolver.FromViewModel(vm); // Spins up a view and sets its DataContext
reg.Add(vw);
reg.Activate(vw);
This all works fine, however I 'd really like to use the Prism navigation framework to do all this stuff for me so that I can do something like this:
_regionManager.RequestNavigate(
"MainRegion",
new Uri("NameOfMyViewModel", UriKind.Relative)
);
and have Prism spin up the ViewModel + View, set up the DataContext and insert the view into the region.
I 've had some success by creating DataTemplates referencing the ViewModel types, e.g.:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Module01">
<DataTemplate DataType="{x:Type local:TestViewModel}">
<local:TestView />
</DataTemplate>
</ResourceDictionary>
...and have the module add the relevant resource dictionary into the applications resources when the module is initialized, but that seems a bit rubbish.
Is there a way to effectively take over view creation from Prism, so that when RequestNavigate is called I can look at the supplied Uri and spin up the view / viewmodel based on that? There’s an overload of RegionManager.RegisterViewWithRegion that takes a delegate that allows you to supply a view yourself, and I guess I’m after something like that.
I think I might need to supply my own IRegionBehaviorFactory, but am unsure what's involved (or even if I am on the right path!).
Any help appreciated!
--
note: Originally posted over at the prism codeplex site
Sure you can do that. I 've found that Prism v4 is really extensible, if only you know where to plug in.
In this case, you want your own custom implementation of IRegionNavigationContentLoader.
Here's how to set things up in your bootstrapper (the example is from a subclass of UnityBootstrapper from one of my own projects):
protected override void ConfigureContainer()
{
// IMPORTANT: Due to the inner workings of UnityBootstrapper, accessing
// ServiceLocator.Current here will throw an exception!
// If you want access to IServiceLocator, resolve it from the container directly.
base.ConfigureContainer();
// Set up our own content loader, passing it a reference to the service locator
// (it will need this to resolve ViewModels from the container automatically)
this.Container.RegisterInstance<IRegionNavigationContentLoader>(
new ViewModelContentLoader(this.Container.Resolve<IServiceLocator>()));
}
The ViewModelContentLoader itself derives from RegionNavigationContentLoader to reuse code, and will look something like this:
public class ViewModelContentLoader : RegionNavigationContentLoader
{
private readonly IServiceLocator serviceLocator;
public ViewModelContentLoader(IServiceLocator serviceLocator)
: base(serviceLocator)
{
this.serviceLocator = serviceLocator;
}
// THIS IS CALLED WHEN A NEW VIEW NEEDS TO BE CREATED
// TO SATISFY A NAVIGATION REQUEST
protected override object CreateNewRegionItem(string candidateTargetContract)
{
// candidateTargetContract is e.g. "NameOfMyViewModel"
// Just a suggestion, plug in your own resolution code as you see fit
var viewModelType = this.GetTypeFromName(candidateTargetContract);
var viewModel = this.serviceLocator.GetInstance(viewModelType);
// get ref to viewResolver somehow -- perhaps from the container?
var view = _viewResolver.FromViewModel(vm);
return view;
}
// THIS IS CALLED TO DETERMINE IF THERE IS ANY EXISTING VIEW
// THAT CAN SATISFY A NAVIGATION REQUEST
protected override IEnumerable<object>
GetCandidatesFromRegion(IRegion region, string candidateNavigationContract)
{
if (region == null) {
throw new ArgumentNullException("region");
}
// Just a suggestion, plug in your own resolution code as you see fit
var viewModelType = this.GetTypeFromName(candidateNavigationContract);
return region.Views.Where(v =>
ViewHasDataContract((FrameworkElement)v, viewModelType) ||
string.Equals(v.GetType().Name, candidateNavigationContract, StringComparison.Ordinal) ||
string.Equals(v.GetType().FullName, candidateNavigationContract, StringComparison.Ordinal));
}
// USED IN MY IMPLEMENTATION OF GetCandidatesFromRegion
private static bool
ViewHasDataContract(FrameworkElement view, Type viewModelType)
{
var dataContextType = view.DataContext.GetType();
return viewModelType.IsInterface
? dataContextType.Implements(viewModelType)
: dataContextType == viewModelType
|| dataContextType.GetAncestors().Any(t => t == viewModelType);
}
// USED TO MAP STRINGS OF VIEWMODEL TYPE NAMES TO ACTUAL TYPES
private Type GetTypeFromName(string typeName)
{
// here you need to map the string type to a Type object, e.g.
// "NameOfMyViewModel" => typeof(NameOfMyViewModel)
return typeof(NameOfMyViewModel); // hardcoded for simplicity
}
}
To stop some confusion about "ViewModel first approach":
You use more a "controller approach", but no "ViewModel first approach". A "ViewModel first approach" is, when you inject your View in your ViewModel, but you wire up both, your ViewModel and View, through a third party component (a controller), what by the way is the (I dont want to say "best", but) most loosely coupled approach.
But to answer your Question:
A possible solution is to write an Extension for the Prism RegionManager that does exactly what you have described above:
public static class RegionManagerExtensions
{
public static void AddToRegion<TViewModel>(
this IRegionManager regionManager, string region)
{
var viewModel = ServiceLocator.Current.GetInstance<TViewModel>();
FrameworkElement view;
// Get View depending on your conventions
if (view == null) throw new NullReferenceException("View not found.");
view.DataContext = viewModel;
regionManager.AddToRegion(region, view);
regionManager.Regions[region].Activate(view);
}
}
then you can call this method like this:
regionManager.AddToRegion<IMyViewModel>("MyRegion");

F#/WPF event binding

I am wandering if there is a way of hooking an event defined in XAML to a F# function of member ? Of course, I could do it diagrammatically but it is kind of inconvenient.
I suppose the question is whether you can specify F# member as an event handler using XAML markup:
<Button x:Name="btnClick" Content="Click!" Click="button1_Click" />
As far as I know, the answer is No.
The way this works in C# is that the registration of event handler is done in C# code (partial class) generated by the designer (you can see that in the obj directory in files named e.g. MainForm.g.cs). F# doesn't have any direct support for WPF designer, so it cannot generate this for you. You'll have to write the code to attach event handlers by hand (but that's quite easy).
I have some examples in my London talk about Silverlight. You can implement the ? operator to get nice access to the XAML elements:
type MainPage() as this =
inherit UserControl()
let uri = new System.Uri("/App;component/MainPage.xaml", UriKind.Relative)
do Application.LoadComponent(this, uri)
// Get button using dynamic access and register handler
let btn : Button = this?btnClick
do btnClick.Click.Add(fun _ -> (* ... *))
The ? operator declaration that I used is:
let (?) (this : Control) (prop : string) : 'T = // '
this.FindName(prop) :?> 'T
It is possible to add binding to a command, eg. using the Command="..." property in the button.
So in you XAML you can have:
<Button Command="{Binding MyCommandHandler}">
Then in your ViewModel code, if you have a member called MyCommandHandler, it'll be bound to the above button. So in your F#, something like:
module ViewModel =
type FuncCommand (canExec:(obj -> bool), doExec:(obj -> unit)) =
let theEvent = new DelegateEvent<EventHandler>()
interface ICommand with
[<CLIEvent>]
member x.CanExecuteChanged = theEvent.Publish
member x.CanExecute arg = canExec(arg)
member x.Execute arg = doExec(arg)
type MyViewModel() =
member this.MyCommandHandler =
new FuncCommand(
(fun _ -> ... SOME CODE WHICH RETURNS TRUE OR FALSE ...),
(fun _ -> ... SOME CODE TO HANDLE THE CLICK ...)
)
You can do it using an attached property:
namespace Foo
open System.Windows
open System.Windows.Controls
open System.Windows.Controls.Primitives
open System.Windows.Media
module Register =
// http://stackoverflow.com/a/14706890/1069200
type internal Marker = interface end
let ClickHandlerProperty = DependencyProperty.RegisterAttached(
"ClickHandler",
typeof<RoutedEventHandler>,
typeof<Marker>.DeclaringType,
PropertyMetadata(null))
let SetClickHandler (element: UIElement, value : RoutedEventHandler) =
element.SetValue(ClickHandlerProperty, value)
let GetClickHandler (element: UIElement) : RoutedEventHandler =
element.GetValue(ClickHandlerProperty) :?> _
let private OnClick (sender : obj) args =
let button = sender :?> UIElement
let handler = GetClickHandler button
if not (obj.ReferenceEquals(handler, null)) then
handler.Invoke(sender, args)
let private initialize =
EventManager.RegisterClassHandler(
typeof<FrameworkElement>,
ButtonBase.ClickEvent,
RoutedEventHandler(OnClick))
Then use it in xaml like this:
<Window ...
xmlns:foo="clr-namespace:Foo;assembly=Foo">
<Button Content="Click!" foo:Register.ClickHandler="{x:Static foo:Bar.OnClicked}" />
</Window>
Where bar is:
namespace Foo
open System.Windows
module Bar =
let OnClicked =
let onClick _ _ = MessageBox.Show "clicked" |> ignore
RoutedEventHandler(onClick)
I don't know f# so the above code can probably be cleaned up a lot.
For the click event David's suggestion to bind the command is probably nicest.
This is now supported in the newer versions of FsXaml, though it works slightly differently than it does in C#.
Using FsXaml, you can define your Xaml and specify your event handler. For example, in a window named "MyWindow", you can do:
<Button Content="Click!" Click="button1_Click" />
In your "code behind" file, you would handle this like so:
type MyWindowBase = XAML<"MyWindow.xaml">
type MyWindow () =
inherit MyWindowBase
override this.button1_Click (_,_) = () // Handle event here

In MVVM with WPF how do I unit test the link between the ViewModel and the View

In MVVM it is normal to connect View to the ViewModel with data binding.
Therefore if the name of a properties changes on one of the Model objects that is databound to there is no compiler error.
When the compiler will not stop a bug, the next thing I think of is “UnitTest”, However
How do you unit test this without
spending forever writing a GUI test?
Is there a system that will check that all the properties that are bound to is valid, (without having to run the UI) that I can call in a unit test?
I am looking for something that will take the view, and then loop over all WPF controls, for each WPF control it will look at all the binding and check if they are valid.
By the way there have been a few good questions about how to make OnPropertyChanged safe, and/or how to test it (But done of these get down to the level of a WPF view.)
How to make Databinding type safe and support refactoring
Automatically INotifyPropertyChanged
workarounds for nameof() operator in C#: typesafe databinding
A Fluent Interface For Testing INotifyPropertyChanged
Automatic Class Tester will test all simple proptites and INotifyPropertyChanged
I have put a bounty on this question, as someone must have thought hard about the problem and come up with soltions.
I think I've come up with something that may work using simple reflection, and adapting some code I've used in the past (the code for the FindBindingsRecursively method was written by Martin Bennedik's as part of his Enterprise WPF Validation Control):
[TestMethod]
public void CheckWpfBindingsAreValid()
{
// instansiate the xaml view and set DataContext
var yourView = new YourView();
yourView.DataContext = YourViewModel;
FindBindingsRecursively(yourView,
delegate(FrameworkElement element, Binding binding, DependencyProperty dp)
{
var type = yourView.DataContext.GetType();
// check that each part of binding valid via reflection
foreach (string prop in binding.Path.Path.Split('.'))
{
PropertyInfo info = type.GetProperty(prop);
Assert.IsNotNull(info);
type = info.PropertyType;
}
});
}
private delegate void FoundBindingCallbackDelegate(FrameworkElement element, Binding binding, DependencyProperty dp);
private void FindBindingsRecursively(DependencyObject element, FoundBindingCallbackDelegate callbackDelegate)
{
// See if we should display the errors on this element
MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Static |
BindingFlags.Public |
BindingFlags.FlattenHierarchy);
foreach (MemberInfo member in members)
{
DependencyProperty dp = null;
// Check to see if the field or property we were given is a dependency property
if (member.MemberType == MemberTypes.Field)
{
FieldInfo field = (FieldInfo)member;
if (typeof(DependencyProperty).IsAssignableFrom(field.FieldType))
{
dp = (DependencyProperty)field.GetValue(element);
}
}
else if (member.MemberType == MemberTypes.Property)
{
PropertyInfo prop = (PropertyInfo)member;
if (typeof(DependencyProperty).IsAssignableFrom(prop.PropertyType))
{
dp = (DependencyProperty)prop.GetValue(element, null);
}
}
if (dp != null)
{
// Awesome, we have a dependency property. does it have a binding? If yes, is it bound to the property we're interested in?
Binding bb = BindingOperations.GetBinding(element, dp);
if (bb != null)
{
// This element has a DependencyProperty that we know of that is bound to the property we're interested in.
// Now we just tell the callback and the caller will handle it.
if (element is FrameworkElement)
{
callbackDelegate((FrameworkElement)element, bb, dp);
}
}
}
}
// Now, recurse through any child elements
if (element is FrameworkElement || element is FrameworkContentElement)
{
foreach (object childElement in LogicalTreeHelper.GetChildren(element))
{
if (childElement is DependencyObject)
{
FindBindingsRecursively((DependencyObject)childElement, callbackDelegate);
}
}
}
}
Really good question. Voted it up. I would like to know the answer too.
One of the best practices I know (suggested by Josh Smith, thanks Gishu for pointing to this) is having base view model class to check in the OnPropertyChanged() method whether property really exists. E.g.:
abstract class ViewModelBase
{
[Conditional("DEBUG")]
public void VerifyPropertyName(string propertyName)
{
// Verify that the property name matches a real,
// public, instance property on this object.
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
if (this.ThrowOnInvalidPropertyName)
throw new ArgumentException(propertyName);
string msg = "Invalid property name: " + propertyName;
Debug.Fail(msg);
}
}
protected void OnPropertyChanged(string propertyName)
{
VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
But this wouldn't help you to find spelling problems in XAML. Hmm... I don't know any existing solution for this. Maybe guys from WPF Disciples could suggest something. I think I would go with PresentationTraceSources.DataBindingSource and add to his Listners collection instance of TextWriterTraceListener and then monitor output. As soon as we get an error or warning on our radar we should fail a test.
Found good example: WPF Snippet - Detecting Binding Errors
Hope this helps. At least a bit :).
Cheers, Anvaka.
I know that this is not the direct answer to your question.
If you know the name of the control element, that you expect to be bound against you can do something like the test below (using nunit). This is the rough version. But here you use expressions and explicitly test that the property is in a binding
[Test]
public void TestBindings()
{
TestBinding<IndividualSolutionViewModel, string>(x => x.Name, "Name", TextBlock.TextProperty);
}
private void TestBinding<TViewModel,TResult>(Expression<Func<TViewModel, TResult>> property, string elementName,
DependencyProperty dependencyProperty)
{
string memberName = ExpressionHelper.GetPropertyName(property); // f.ex v => v.Name will return Name
TestBinding(memberName, elementName, dependencyProperty);
}
private void TestBinding(string memberName, string elementInControlName, DependencyProperty dependencyProperty)
{
//object viewModel = new IndividualSolutionViewModel();
var view = new IndividualSolutionView();
//Assert.That(view.DataContext, Is.EqualTo(viewModel));
var element = view.FindName(elementInControlName);
Assert.That(element, Is.Not.Null, string.Format("Unable to find the element {0} in view {1}", elementInControlName, view.Name));
Assert.That(element, Is.InstanceOf(typeof(DependencyObject)));
var binding = BindingOperations.GetBinding(element as DependencyObject, dependencyProperty);
Assert.That(binding, Is.Not.Null, string.Format("Could not find a binding for the control {0}", elementInControlName));
Assert.That(binding.Path.Path, Is.EqualTo(memberName));
}
Ps. You have to add this to the app.config
<configSections>
<sectionGroup name="NUnit">
<section type="System.Configuration.NameValueSectionHandler"
name="TestRunner"></section>
</sectionGroup>
</configSections>
<NUnit>
<TestRunner>
<add value="STA" key="ApartmentState"></add>
</TestRunner>
</NUnit>
There is also this possibility, that might give you some ideas. THe gist of the idea is property names that you would be binding to are exposed as static string properties. If a binding property name changed you would get a compilation error.
I have not had the opportunity to actually test this technique myself - but it does look interesting:
http://www.codeproject.com/Articles/42036/Project-Metadata-Generation-using-T4
As Anvaka points out, using a base class for your view model that checks property names can help avoid this particular problem (though it won't tell you when your VM class does its own property-change notification and ignores the method in the base class, not that I've ever seen anything like that happen in my code).
And you can (and should) instrument your code so that things that aren't working fail in a way that's visible to you. The thing that's kind of paradoxical about this is that if you know what things may fail and you watch them, they won't, because the fact that you're watching them will keep you from making the mistakes that lead them to fail (like writing a template selector that doesn't always return a template).
But fundamentally, the view is the UI, so I would be pretty surprised to find methods of testing it that weren't also methods for testing the UI.

Unit test WPF Bindings

I am trying to unit test my WPF databindings using the test suit provided by Microsoft Team System. I would like to be able to test the bindings without showing the window because most of my tests will be for user controls and not actually on a window. Is this possible or is there a better way to do it? The code below works if I show the window, but if I don't, the bindings don't update.
Window1_Accessor target = new Window1_Accessor();
UnitTestingWPF.Window1_Accessor.Person p = new UnitTestingWPF.Window1_Accessor.Person() { FirstName = "Shane" };
Window1 window = (target.Target as Window1);
window.DataContext = p;
//window.Show(); //Only Works when I actually show the window
//Is it possible to manually update the binding here, maybe? Is there a better way?
Assert.AreEqual("Shane", target.textBoxFirstName.Text); //Fails if I don't Show() the window because the bindings aren't updated
While looking for a solution to convert WPF binding errors into exception, I figured out that it can also be used in a unit test project.
The technique is very simple:
Derive a TraceListener that throws instead of logging
Add that listener to PresentationTraceSources.DataBindingSource
Please see the complete solution on GitHub, it includes a unit test project.
Shane, if what you're really worried about is a binding breaking silently, you should look at redirecting the binding traces to somewhere you can examine. I'd start here:
http://blogs.msdn.com/mikehillberg/archive/2006/09/14/WpfTraceSources.aspx
Other than that, I agree with Gishu that bindings aren't good candidates for unit testing, mainly due to the automagic going on that Gishu mentioned in the "Epilogue". Instead focus on making sure the underlying class behaves correctly.
Note, too, that you can get even more robust traces using the PresentationTraceSources class:
http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.aspx
Hope that helps!
Eyeball it.
This kind of declarative markup rarely breaks.. unless someone goes in manual and screws it up. Even then, you can fix it within minutes. IMHO the cost of writing such tests far outweigh the benefits.
Update[Dec3,08]: Alrighty then.
The test is just testing that the textbox has the value "FirstName" as the Path property of the binding. If I change/refactor FirstName to JustName in the actual data source object, the test would still pass since it is testing against an anonymous type. (Green test when code broken - TDD Antipattern: The Liar)
If your aim is to verify that FirstName has been specified in XAML,
Assert.AreEqual("FirstName", txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).ParentBinding.Path.Path);
If you really must catch broken bindings via unit tests (and don't want to show the UI), use the real data source... struggled for a while and came up with this.
[Test]
public void TestTextBoxBinding()
{
MyWindow w = new MyWindow();
TextBox txtBoxToProbe = w.TextBox1;
Object obDataSource = w; // use 'real' data source
BindingExpression bindingExpr = BindingOperations.GetBindingExpression(txtBoxToProbe, TextBox.TextProperty);
Binding newBind = new Binding(bindingExpr.ParentBinding.Path.Path);
newBind.Source = obDataSource;
txtBoxToProbe.SetBinding(TextBox.TextProperty, newBind);
Assert.AreEqual("Go ahead. Change my value.", txtBoxToProbe.Text);
}
Epilogue:
There's some real covert stuff happening in the call to Window.Show(). It somehow magically sets up the DataItem property after which data binding starts working.
// before show
bindingExpr.DataItem => null
bindingExpr.Status => BindingStatus.Unattached
// after show
bindingExpr.DataItem => {Actual Data Source}
bindingExpr.Status => BindingStatus.Active
Once the Binding is Active, I guess you can force textbox updates via code like this..
txtBoxToProbe.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
Once again, I voice my reluctance against this approach. Getting NUnit to run in STA was a pain..
Combining advice I came across in a number of SO posts I wrote the following class which works very well to test WPF bindings.
public static class WpfBindingTester
{
/// <summary>load a view in a hidden window and monitor it for binding errors</summary>
/// <param name="view">a data-bound view to load and monitor for binding errors</param>
public static void AssertBindings(object view)
{
using (InternalTraceListener listener = new InternalTraceListener())
{
ManualResetEventSlim mre = new ManualResetEventSlim(false);
Window window = new Window
{
Width = 0,
Height = 0,
WindowStyle = WindowStyle.None,
ShowInTaskbar = false,
ShowActivated = false,
Content = view
};
window.Loaded += (_, __) => mre.Set();
window.Show();
mre.Wait();
window.Close();
Assert.That(listener.ErrorMessages, Is.Empty, listener.ErrorMessages);
}
}
/// <summary>Is the test running in an interactive session. Use with Assume.That(WpfBindingTester.IsAvailable) to make sure tests only run where they're able to</summary>
public static bool IsAvailable { get { return Environment.UserInteractive && Process.GetCurrentProcess().SessionId != 0; } }
private class InternalTraceListener : TraceListener
{
private readonly StringBuilder _errors = new StringBuilder();
private readonly SourceLevels _originalLevel;
public string ErrorMessages { get { return _errors.ToString(); } }
static InternalTraceListener() { PresentationTraceSources.Refresh(); }
public InternalTraceListener()
{
_originalLevel = PresentationTraceSources.DataBindingSource.Switch.Level;
PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
PresentationTraceSources.DataBindingSource.Listeners.Add(this);
}
public override void Write(string message) {}
public override void WriteLine(string message) { _errors.AppendLine(message); }
protected override void Dispose(bool disposing)
{
PresentationTraceSources.DataBindingSource.Listeners.Remove(this);
PresentationTraceSources.DataBindingSource.Switch.Level = _originalLevel;
base.Dispose(disposing);
}
}
}
you can try Guia.
With it you can unit-test your UserControl and check if the data binding is correct. You have to show the window though.
Here is an example. It starts a new instance of your UserControl and sets its DataContext and then checks if the textbox is set to the right value.
[TestMethod]
public void SimpleTest()
{
var viewModel = new SimpleControlViewModel() {TextBoxText = "Some Text"};
customControl = CustomControl.Start<SimpleUserControl>((control) => control.DataContext = viewModel);
Assert.AreEqual("Some Text", customControl.Get<TextBox>("textbox1").Value);
customControl.Stop();
}

Resources