wpf DataContext error in Designer - wpf

I have a presentation involving (3) DataGrids that are almost the same, but different enough that it seems like a cleaner design to do just the whole thing in code.
It is still raw (class diagram below), but works the way I want except for one thing! The visual studio designer can't figure out the late binding of the DataContext, so it throws an error.
An example of how I am pulling the grid's data context for use in a given column is below, as well as the error I get.
Does s anyone see a way to make the designer happy with the existing code?
Does anyone have a suggestion for a better approach?
I know there are ways to give Blend some notion of data but I don't as yet know Blend.
Cheers,
Berryl
CODE
public abstract class TimesheetGridColumn : DataGridTextColumn
{
...
protected ActivityCollectionViewModel _GetDataContext() { return (ActivityCollectionViewModel) DataGridOwner.DataContext; }
public virtual void SetHeader() {
var tb = new TextBlock
{
Text = _GetHeaderText(),
ToolTip = _GetHeaderToolTip(),
};
Header = tb;
}
....
}
public class ActivityDescriptionColumn : TimesheetGridColumn
{
...
*** WORKS at RUNTIME but DESIGNER does not know that *******
protected override string _GetHeaderText() {
return _GetDataContext().PresentationSubject;
}
}
XAML SNIPPET & DESIGNER ERROR
<Expander Header="{Binding DisplayName}" BorderThickness="1" IsExpanded="True">
<dataGrid:ActivityDataGrid /> <=============== simple but error
</Expander>
System.NullReferenceException
Object reference not set to an instance of an object.
at ...ColumnSubclasses.ActivityDescriptionColumn._GetHeaderText() in ActivityDescriptionColumn.cs:line 24
CLASS DIAGRAM

If all you need is to get the designer to work again, you can probably put a DesignerProperties.GetIsInDesignModecheck in somewhere.
How about:
protected override string _GetHeaderText()
{
if (!DesignerProperties.GetIsInDesignMode(this))
{
return _GetDataContext().PresentationSubject;
}
else
{
return "Design Mode Text";
}
}

You may be able to solve your designer problem with the Designer Attributes that are a part of WPF. Follow this link to an MSDN article on Design-time attributes and look specifically at the d:DataContext attribute. If you can create a sample implementation of the class that your grids are binding to, you may be able to get the designer working for you again.

Related

How to locate the source of a binding error?

How can I figure out what line of xaml contains the troublesome binding When my debug output is full of lines like the following:
System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='UW.Entities.ProgramModel.UWProgram' BindingExpression:Path=; DataItem='RuntimeType' (HashCode=24995901); target element is 'DataGridCollectionViewSource' (HashCode=60976864); target property is 'Source' (type 'Object')
I don't know how to interpret this in a way that can let me find the responsible line of xaml. I can't even figure out what xaml file the error is coming from. Is there some way to get more information when these errors occur?
'UW.Entities.ProgramModel.UWProgram' is just a type - I don't know what the object being bound to is. I also have lots of DataGridCollectionViewSources in various bits of xaml, all who's property 'Source' is bound to something which may or may not have that type (again - no easy way to tell).
If you do not know which binding fails
I would use the Snoop utility for this purposes. In short - at the top-left corner above the visual tree, you'll find a drop-down list which allows filtering visuals, just select Visuals with binding Error. See online documentation for more details.
If you know which binding fails
Sometime you know which binding fails but was not able to find a source fo the problem since binding is pretty tricky, for instance TemplateBindings, bindings which refer to a DataContext of another control, etc.. I found helpful putting a TextBlock which Text property is bound to the same binding source in this way you can see what exactly bound since TextBlock will display a type name of a bound object.
For instance you have following failed binding:
<ItemsControl ItemsSource="{Binding Parent.DataContext.ActiveItem.DataContext}" />
<!-- See what is bound, if failed - try previous level -->
<TextBlock Text="{Binding Parent.DataContext}" />
<TextBlock Text="{Binding Parent.Inner.Items}" />
<TextBlock Text="{Binding Parent.Inner}" />
Useful links:
Debugging Data Bindings in a WPF or Silverlight Application
Nice trick using special DebugConverter which allows break a debugger whilst doing a binding, see Debugging WPF DataBinding article
I have been happily using the wonderful snippet from 'Switch on the Code' to detect and report binding errors since it was first published in 2009...
http://www.switchonthecode.com/tutorials/wpf-snippet-detecting-binding-errors
edit: still works excellently on VS2012 (Sept 2013)
Update 25 Jan 2016
The link appears broken, so I'll paste in the relevant snippets...
using System.Diagnostics;
using System.Text;
using System.Windows;
namespace SOTC_BindingErrorTracer
{
public class BindingErrorTraceListener : DefaultTraceListener
{ //http://www.switchonthecode.com/tutorials/wpf-snippet-detecting-binding-errors
private static BindingErrorTraceListener _Listener;
public static void SetTrace()
{ SetTrace(SourceLevels.Error, TraceOptions.None); }
public static void SetTrace(SourceLevels level, TraceOptions options)
{
if (_Listener == null)
{
_Listener = new BindingErrorTraceListener();
PresentationTraceSources.DataBindingSource.Listeners.Add(_Listener);
}
_Listener.TraceOutputOptions = options;
PresentationTraceSources.DataBindingSource.Switch.Level = level;
}
public static void CloseTrace()
{
if (_Listener == null)
{ return; }
_Listener.Flush();
_Listener.Close();
PresentationTraceSources.DataBindingSource.Listeners.Remove(_Listener);
_Listener = null;
}
private StringBuilder _Message = new StringBuilder();
private BindingErrorTraceListener()
{ }
public override void Write(string message)
{ _Message.Append(message); }
public override void WriteLine(string message)
{
_Message.Append(message);
var final = _Message.ToString();
_Message.Length = 0;
MessageBox.Show(final, "Binding Error", MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
}
And to set it up/initialize it...
namespace WpfListeningForTraceErrors
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
BindingErrorTraceListener.SetTrace();
InitializeComponent();
}
}
}
You can add this to every control that binds
PresentationTraceSources.TraceLevel="High"
And run the program in debug, the detailed binding information will appear in your Output window. It may help a bit. You can also create a pass though converter to catch an error (catches the problem some times but not always). There are no good tools for debugging XAML in general that I am aware of.
You can download a tool called Snoop that will allow you to debug bindings. It provides a view of your WPF applications visual tree higlighting any binding errors that it finds.
You can get some basic information about binding errors in the Output Window in Visual Studio. It will show the binding expression path error and the line on which the error occured.
In VisualStudio goto Tools->Extentions and Updates->(download Output Enhancer). When you build your solution you will get the exact kind of error message you posted in Red color if there is a binding error.

Getting Silverlight MVVM working with Expression Blend design time data?

I am a big proponent of the MVVM pattern with Silverlight. Currently I wire the ViewModel up to the View by newwing up the ViewModel in the code behind of the view, thusly:
public partial class SomePage : UserControl
{
public SomePage()
{
InitializeComponent();
// New up a ViewModel and bind to layout root
var vm = new SomeViewModel();
LayoutRoot.DataContext = vm;
}
}
And then all the binding is handled in the View and all the logic is handled in the ViewModel, as the pattern intends.
However, wiring them up this way means that the designer doesn't work well, and I can't use Expression Blend design time data. I know that there are libraries such as MVVM Light that will help to get all this working, but I prefer not to bring in a library, as it is "one more thing" to have to deal with.
Is there a simple pattern for getting MVVM wired up in Silverlight while maintaining designer functionality, especially in Blend? I've done some Googling but there are so many outdated articles out there and so much confusion between WPF and Silverlight and older versions that I have a hard time figuring out which to use.
BTW I'm focused on SL4 with VS2010 if it matters.
There are a few methods you can use.
First, let Expression's Sample Data and design-time attributes (i.e. d:DataContext) take over in the designer. In your code, you would simply condition the view model binding:
if (!DesignerProperties.IsInDesignTool)
{
var vm = new SomeViewModel();
LayoutRoot.DataContext = vm;
}
Second, you can have a special design-time view model that you bind instead:
LayoutRoot.DataContext = DesignerProperties.IsInDesignTool ?
new DesignViewModel() : new MyViewModel();
Finally, another way is to manage the data within the view model. I don't like this because it spreads the responsibility across all view models, but you have more precision:
// constructor
private Widget[] _designData = new[] { new Widget("Test One"), new Widget("Test Two") };
public MyViewModel()
{
if (DesignerProperties.IsInDesignTool)
{
MyCollection = new ObservableCollection<Widget>(_designData);
}
else
{
MyService.Completed += MyServiceCompleted;
MyService.RequestWidgets();
}
}
private void MyServiceCompleted(object sender, AsynchronousEventArgs ae)
{
// load up the collection here
}
Hope that helps!
What you are looking for is "Blendibility". MVVM Light has a concept of the ViewModelLocator and I'm using it on a project with great results.
Here's a great post by Roboblob on the topic. http://blog.roboblob.com/2010/01/17/wiring-up-view-and-viewmodel-in-mvvm-and-silverlight-4-blendability-included/ This post has an example solution so it really helps in the understanding. Rob improves on the MVVM Light implementation and I think does a good job.
I've run into similar issues designing WPF applications. One trick I've learned is to declare an xmlns so you can embed an array of objects in XAML:
xmlns:coll="clr-namespace:System.Collections;assembly=mscorlib"
You can then drop an ArrayList of just about anything into the XAML:
<coll:ArrayList x:Key="questions">
<local:QuestionItem Title="FOO"></local:QuestionItem>
</coll:ArrayList>
You can then set the ItemsSource of a grid, listbox, etc to the array:
<ListBox x:Name="lstStuff" ItemsSource="{StaticResource questions}" />
This technique will allow you to "preview" the look and feel of list-style controls in the designer. It doesn't solve all problems with visual prototyping, but it goes a long way and can be adapted to several different scenarios.
You could, for example, declare your local namespace as an xmlns, then drop mocks of your ViewModel into the Resources of the window or control. I haven't tried this but theoretically you could get a complete design-time preview.

How to properly use a Subclassed silverlight control?

I created this class where I wanted to override this specific event for the content control.
public class MyContentControl : ContentControl
{
protected override void OnKeyUp(KeyEventArgs e)
{
//do something
//..........
e.Handled = true;
}
}
However when I am using this control in my XAML everything compiles and works fine, but I am getting a runtime exception and I am not sure exactly why? Could someone point me in the right directions....
The exception I get is
XamlParseException
UPDATED (Shows where abouts of the exceptions)
In the XAML I have:
xmlns:ctrls="clr-namespace:SilverlightProject.CustomControls"
and I use it like:
<ctrls:MyContentControl Grid.Column="0" x:Name="_contentControl" VerticalAlignment="Center" HorizontalAlignment="Center" />
Content controls require a default template to be created somewhere (e.g. in generic.xaml). They do not have a matching XAML file like user controls.
If you can provide more information, I can show you how to create an appropriate template.
There are many reasons for this.
To start with. Give the fully qualified namespace.
Instead of
xmlns:ctrls="clr-namespace:SilverlightProject.CustomControls"
Use
xmlns:ctrls="clr-namespace:SilverlightProject.CustomControls;assembly=YourAssebmlyName"
If that, doesn't help.
You directly attach your control with the application. Then, enable Debug -> Exceptions. Check Thrown option for the CLR execetion checkbox. You have fair amount of possibility to get to know the cause.

MVVM ViewModel to View Messaging

MVVM question.
Messaging between ViewModel and View, how is it best implemented?
The application has some points of “user communication” such as: “You have entered comments for this selection. Do you wish to save or discard” when the value of a Yes/No/NA selection changes.
So I need some proscribed way of the View binding to the ViewModel’s “messages” .
I went down path starting with MVVM Foundation's Messenger. However that is more of a system-wide broadcast then a event/subscriber model. So, if the app has two instances of a View (Person1 EditView and Person2 EditView) open they both get the message when one ViewModel publishes the "do you want to save" message.
What approach have you used?
Thanks
Andy
For all of this you would use binding as your method for "communication". For example, the confirmation message might be shown or hidden based on properties set in your ViewModel.
Here's the View
<Window.Resources>
<BoolToVisibilityConverter x:key="boolToVis" />
</Window.Resources>
<Grid>
<TextBox Text="{Binding Comment, Mode=TwoWay}" />
<TextBlock Visibility="{Binding IsCommentConfirmationShown,
Converter={StaticResource boolToVis}"
Text="Are you sure you want to cancel?" />
<Button Command="CancelCommand" Text="{Binding CancelButtonText}" />
</Grid>
And here is your ViewModel
// for some base ViewModel you've created that implements INotifyPropertyChanged
public MyViewModel : ViewModel
{
//All props trigger property changed notification
//I've ommited the code for doing so for brevity
public string Comment { ... }
public string CancelButtonText { ... }
public bool IsCommentConfirmationShown { ... }
public RelayCommand CancelCommand { ... }
public MyViewModel()
{
CancelButtonText = "Cancel";
IsCommentConfirmationShown = false;
CancelCommand = new RelayCommand(Cancel);
}
public void Cancel()
{
if(Comment != null && !IsCommentConfirmationShown)
{
IsCommentConfirmationShown = true;
CancelButtonText = "Yes";
}
else
{
//perform cancel
}
}
}
This is not a full sample (the only option is yes! :) ), but hopefully this illustrates that your View and your ViewModel are almost one entity and not two that are making phone calls to each other.
Hope this helps.
What Anderson describes is probably sufficient for the particular requirement you describe. However, you may want to look into Expression Blend Behaviors which provide powerful support for interactions between view models and views, which may be useful in more complex scenarios - using binding for 'messages' will only get you so far.
Note, the expression blend SDK is freely available - you don't have to use Expression Blend to use the SDK or the behavior; although the Blend IDE does have better inbuilt support for 'drag and drop' of behaviors.
Also, note each 'behavior' is a component - in other word it's an extensible model; there are a few built-in behaviors in the SDK, but you can write your own behaviors.
Here are some links. (Note, don't let the 'silverlight' in the URL mislead you - behaviors are supported for both WPF and Silverlight):
information
Blend SDK
video on behaviors

UserControl that has a generic class in its inheritance tree

I'm trying to create a UserControl that inherits from a generic class. It does not directly inherit from a generic class, but through an intermediate class that does not use generics. This compiles and works at runtime, but I get an error at design time.
Here's my generic parent class:
Public Class GenericParent(Of T)
Inherits UserControl
End Class
Here's my non-generic parent class:
Public Class NonGenericParent
Inherits GenericParent(Of String)
End Class
Here's my XAML:
<local:NonGenericParent x:Class="SilverlightApplication5.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SilverlightApplication5"
Width="400" Height="300">
<StackPanel>
<Button Content="Hello"/>
</StackPanel>
</local:NonGenericParent>
The IntelliSense parser gives the following errors:
The property 'Width' was not found in type 'NonGenericParent'.
The property 'Height' was not found in type 'NonGenericParent'.
The type 'NonGenericParent' does not support direct content.
It is as though IntelliSense can't see up the inheritance tree past the GenericParent class. I've tried specifying the ContentPropertyAttribute directly on the SilverlightApplication5.Page class, the NonGenericParent class, and it does not work.
I've read that the TypeArguments attribute is not supported in Silverlight 2.0. That is why I've created the intermediate NonGenericParent class.
If anybody has any ideas how to silence these errors I'd be eager to hear them.
Update: We've opened a support ticket with MSFT, I'll update this with whatever their solution is.
We've received word from Microsoft that this is not likely to be fixed in future versions. After they bounced the problem around trying to find the responsible group, it appears that this problem belongs to their WPF developer group, which is where the 'not going to fix it' answer came from.
In the meantime, we've updated our code to yank out the generics from the parent classes until I guess XAML 2009.
Not sure about silverlight, but this compiles and runs as expected in c#:
class GenericObject[T] : UserControl
{
}
class StaticObject : GenericObject[Int32]
{
public Int32 wide { get { return this.Width; } }
}
private void Form1_Load(object sender, EventArgs e)
{
StaticObject so = new StaticObject();
this.Text = so.wide.ToString();
}
So if it compiles against the clr, it should work just fine.
Could be just an intellisense bug as you're suggesting. Normally I'd advise against ignoring comiler warnings, but in this case it seems that the warning is not valid.
edit: substituted angle brackets with square brackets cause SO stripped them.
Despite being at 2.0 silverlight (and especially the VS2008 tweaks for silverlight) are still very young. There are still quirks in the IDE stuff.
Do you still have the problem even after a sucessful build?
This blog post seems to be related to your issue:
http://blogs.msdn.com/b/wpfsldesigner/archive/2010/01/22/known-issue-controls-deriving-from-a-generic-base-class-must-be-in-separate-assembly.aspx
For Silverlight it seems that you must have 3 classes for this to work.

Resources