Silverlight, Unity and INotifyPropertyChanged - silverlight

I'm starting a new Silverlight project at the moment, and I'm having issues where by Unity is throwing an exception if my ViewModel (which it is instantiating for me) contains the RaisePropertyChanged event.
I looks like this:
public class AddNewClientViewModel : ViewModelBase {
private Visibility _extraClientFieldsVisible;
public Visibility ExtraClientFieldsVisible {
get {
return _extraClientFieldsVisible;
}
set {
_extraClientFieldsVisible = value;
base.RaisePropertyChanged("ExtraClientFieldsVisible");
}
}
public AddNewClientViewModel(IMyInterface blah) {
ExtraClientFieldsVisible = Visibility.Collapsed;
}
ViewModelBase which it inherits looks like this:
public abstract class ViewModelBase : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The full stack trace is noted below, but it seems like calling the RaisePropertyChanged event during the constructor causes Unity to blowup.
Here's the full stack trace of the error:
Microsoft.Practices.Unity.ResolutionFailedException was unhandled by user code
Message="Resolution of the dependency failed, type = \"ClientSide.ViewModels.AddNewClientViewModel\", name = \"\". Exception message is: The current build operation (build key Build Key[ClientSide.ViewModels.AddNewClientViewModel, null]) failed: Object reference not set to an instance of an object. (Strategy type BuildPlanStrategy, index 3)"
TypeRequested="AddNewClientViewModel"
StackTrace:
at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name)
at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name)
at Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name)
at Microsoft.Practices.Unity.UnityContainerBase.Resolve(Type t)
at Microsoft.Practices.Unity.UnityContainerBase.Resolve[T]()
at ClientSide.Framework.ServiceLocator.get_AddNewClientViewModel()
InnerException: Microsoft.Practices.ObjectBuilder2.BuildFailedException
Message="The current build operation (build key Build Key[ClientSide.ViewModels.AddNewClientViewModel, null]) failed: Object reference not set to an instance of an object. (Strategy type BuildPlanStrategy, index 3)"
BuildKey="Build Key[ClientSide.ViewModels.AddNewClientViewModel, null]"
ExecutingStrategyIndex=3
ExecutingStrategyTypeName="BuildPlanStrategy"
StackTrace:
at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.Builder.BuildUp(IReadWriteLocator locator, ILifetimeContainer lifetime, IPolicyList policies, IStrategyChain strategies, Object buildKey, Object existing)
at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name)
InnerException: System.NullReferenceException
Message="Object reference not set to an instance of an object."
StackTrace:
at ClientSide.ViewModels.ViewModelBase.RaisePropertyChanged(String propertyName)
at ClientSide.ViewModels.AddNewClientViewModel.set_ExtraClientFieldsVisible(Visibility value)
at ClientSide.ViewModels.AddNewClientViewModel..ctor(IDataCore dataCore)
at BuildUp_ClientSide.ViewModels.AddNewClientViewModel(IBuilderContext )
at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
InnerException:
So I'm hitting a NullReferenceException. I can't just work out how...

Why not just check for null in RaisePropertyChanged()?
After all, it's not going to cause adverse side effects...

Related

Asynchronous UI Pattern on UWA

I am following this great article from Stephen about asynchronous UI, but unfortunately this does not apply to Universal Windows Apps, since CommandManager class is not available.
How can I workaround this limitation?
This is the base type for Async Commands:
public abstract class AsyncCommandBase : IAsyncCommand
{
public abstract bool CanExecute(object parameter);
public abstract Task ExecuteAsync(object parameter);
public async void Execute(object parameter)
{
await ExecuteAsync(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
protected void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
As pointed in the comments, this "pattern" shouldn't be used because of it's impact on performance when you have many commands registered.
Any call to CommandManager.InvalidateRequerySuggested() will force WPF to validate every single registered command and it's CanExecute(...) methods.
Instead, just declare the event and only let WPF register to it
public abstract class AsyncCommandBase : IAsyncCommand
{
...
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
// C# 6.0, otherwise assign the handler to variable and do null check
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
...
}
Whenever you want to invalidate the command you still just use command.RaiseCanExecuteChanged();. If you want to trigger revalidation of multiple commands, you need to manage it yourself (i.e. creating a CompoundCommand or something similar where you register your commands to groups).

XAML WPF Validation

I am really struggling to find a WPF validation pattern that is easily maintainable. I have been doing some web work, and I was really impressed at how easy validation is in AngularJS. So I may have unrealistic expectations of what WPF will do. The solution I have now seems like it has a bunch of garbage. Here is the XAML I have right now. I don't like having to create the DataResource, and it seems far too verbose. Any suggestions?
<local:DataResource x:Key="RequireFcpaGovernmentRelationsText" BindingTarget="{Binding Vendor.RequireFcpaGovernmentRelationsText}" />
<TextBox MaxLength="50" Width="350" HorizontalAlignment="Left">
<Binding Path="Vendor.FcpaGovernmentRelationsText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:RequiredFieldRule ValidationStep="UpdatedValue" RequireIf="{local:DataResourceBinding DataResource={StaticResource RequireFcpaGovernmentRelationsText}}" RequiredMessage="Please specify government relations."/>
</Binding.ValidationRules>
</Binding>
</TextBox>
Unfortunately, WPF is very verbose by nature. It isn't really fair to compare it to a web technology. The DataResource is needed because of the way that WPF manages the DataContext. We have started doing more and more web project because WPF just doesn't keep up.
This question comes up regularly, and things also change in the .NET world, so let's come up with a current solution that, unlike many snippets here and there, works and is easily maintanable. It will use INotifyDataErrorInfo that's appeared in .NET 4.5.
Make sure you have a base class that you inherit all your data classes from. Make this base class implement INotifyDataErrorInfo:
public abstract class ObjectBase<T> : INotifyDataErrorInfo, INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
private readonly Dictionary<string, List<string>> StoredErrors = new();
protected void OnPropertyChanged(string propertyName) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
if (!string.IsNullOrEmpty(propertyName))
Validate(propertyName);
}
Using INotifyPropertyChanged is not strictly required but you probably want to use that, anyway, and it's easy to combine both.
protected void OnErrorsChanged(string propertyName) =>
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
public bool HasErrors => StoredErrors.Any();
public IEnumerable GetErrors(string propertyName) => StoredErrors.GetValueOrDefault(propertyName);
protected void AddError(string propertyName, string error) {
if (!StoredErrors.ContainsKey(propertyName))
StoredErrors[propertyName] = new List<string>();
if (!StoredErrors[propertyName].Contains(error)) {
StoredErrors[propertyName].Add(error);
OnErrorsChanged(propertyName);
}
}
protected void ClearErrors(string propertyName) {
if (StoredErrors.ContainsKey(propertyName)) {
StoredErrors.Remove(propertyName);
OnErrorsChanged(propertyName);
}
}
You have two approaches for the actual validation logic, you can select either or even combine them. You can add code to your properties that check for your validation conditions and set the errors if those conditions are not met. Or, you can use attributes on your properties to make it automatic. Only add these extra functions if you plan to use the second approach as well:
public void ValidateAll() {
foreach (var prop in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
Validate(prop.Name);
}
protected void Validate(string propertyName) {
ClearErrors(propertyName);
var prop = GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
var validationAttributes = prop?.GetCustomAttributes(typeof(ValidationAttribute)) ?? new List<Attribute>();
if (validationAttributes.Any()) {
var validationResults = new List<ValidationResult>();
object value = prop.GetValue(this);
if (!Validator.TryValidateProperty(value, new ValidationContext(this, null, null) { MemberName = propertyName }, validationResults)) {
foreach (var attributeValidationResult in validationResults)
AddError(propertyName, attributeValidationResult.ErrorMessage);
}
}
}
That's a bit of a boilerplate all right, but it only needs to go into your base class and the actual data classes will use it very simply:
public class Person : ObjectBase<Person> {
private string name;
[Required(ErrorMessage = "Name is required")]
public string Name {
get => name;
set {
name = value;
OnPropertyChanged(nameof(Name));
}
}
private string address;
public string Address {
get => address;
set {
address = value;
OnPropertyChanged(nameof(Address));
ClearErrors(nameof(Address));
if (address.IsEmpty()) //your own functions
AddError(nameof(Address), "Address is required");
if (address.IsInvalid()) //your own functions
AddError(nameof(Address), "Invalid address");
}
}
You can observe the two approaches here. Either you use attributes like Required, StringLength, etc (WPF has quite a few of them) or you can create your own by inheriting ValidationAttribute and providing an IsValid() override. Or you can use simple conditional logic to set errors. Or you can mix those approaches, both in the same data class, or even in the same property -- whichever you find easier to use and more maintainable.
This is already mostly automatic, but using fields in dialogs might require a little bit more plumbing. Use a CanExecute callback with your OK button command handler:
<CommandBinding Command="{StaticResource DoOk}" Executed="Ok" CanExecute="CanOk" />
private void CanOk(object sender, CanExecuteRoutedEventArgs e) =>
e.CanExecute = !YourData?.HasErrors ?? false;
private void Ok(object sender, ExecutedRoutedEventArgs e) {
YourData.ValidateAll();
if (!YourData.HasErrors) {
DialogResult = true;
}
}
This only allows OK to be enabled if there are no validation errors, and makes sure that the dialog can't be finished even if it's enabled but there are errors (which is usually the case right after opening the dialog but before actually editing the fields).

Drag Drop for Files AND also Folders

So I looked at this link before:
http://blogs.msdn.com/b/delay/archive/2009/10/26/creating-something-from-nothing-developer-friendly-virtual-file-implementation-for-net.aspx
The class works flawlessly for Files, but it doesn't support directory's etc, does anyone have any idea how I can change the class to support it, I"m no pinvoke whiz. I've tried a million different things, overriding some code to do File Copy and Directory creation of my drop source into the TEMP directory and attempting to trigger a FileDrop, but this locks up the app entirely.
This leads me to believe that there must be a better way to enable directory structure creation as well.
The main part of the Drag and Drop operation is the DragDrop.DoDragDrop method. From the DragDrop.DoDragDrop Method page on MSDN:
public static DragDropEffects DoDragDrop(
DependencyObject dragSource,
Object data,
DragDropEffects allowedEffects
)
Of particular interest is the data parameter:
A data object that contains the data being dragged.
Notice how this parameter is of type Object, so it's completely up to you as to what object you use in the operation. Now I'm not sure what code you found from the page that you linked to, but if I were trying to drag and drop files and folders, I wouldn't need special classes to do it for me.
The simplest way to do that is to just pass the file and/or folder paths instead of the actual data. The control that the data is dropped on can access the data using the file paths just as easily as the drag source. You should be able to locate the DragDrop.DoDragDrop method from your code and easily adapt that code.
If you want to do Drag and Drop operations in the correct way, then I'd recommend that you take a look at the Drag and Drop Overview page on MSDN. It fully explains what to do and provides several code examples.
To implement drag and drop in MVVM without much experience in WPF, you can refer to 5 steps; I will outline these...
Step 1: Attached Behaviours
Add a new class to your project called Behaviours. It should look like this...
public static class Behaviours
{
#region DandBehaviour
public static readonly DependencyProperty DandBehaviourProperty =
DependencyProperty.RegisterAttached("DandBehaviour", typeof(ICommand), typeof(Behaviours),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.None,
OnDandBehaviourChanged));
public static ICommand GetDandBehaviour(DependencyObject d)
{
return (ICommand)d.GetValue(DandBehaviourProperty);
}
public static void SetDandBehaviour(DependencyObject d, ICommand value)
{
d.SetValue(DandBehaviourProperty, value);
}
private static void OnDandBehaviourChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Grid g = d as Grid;
if (g != null)
{
g.Drop += (s, a) =>
{
ICommand iCommand = GetDandBehaviour(d);
if (iCommand != null)
{
if (iCommand.CanExecute(a.Data))
{
iCommand.Execute(a.Data);
}
}
};
}
else
{
throw new ApplicationException("Non grid");
}
}
#endregion
}
This class implements an attached dependency property which can be reached from both your Xaml and your View Model. It hooks the "Drop" event and invokes a command on it.
Step 2: Instrument the Xaml
In this step you need to add the name space to the Xaml so that it can find the behaviours class in Step 1. It looks something like this...
xmlns:b="clr-namespace:DdMvvm"
This statement assigns the alias 'b' to the behaviours. Then you tell the WPF root window to accept drops...
AllowDrop="true"
Then you can add the behaviour to your logical tree thusly...
<Grid AllowDrop="True" b:Behaviours.DandBehaviour="{Binding DandCommand}">
<DockPanel Background="Bisque" AllowDrop="True"/>
</Grid>
Step 3: Add command support
Download Josh Smith's 'Relay Command' from http://msdn.microsoft.com/en-us/magazine/dd419663.aspx For completeness purposes, it is given here as...
public class RelayCommand : ICommand
{ //http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
}
Step 4: Write the View Model
A View Model looks like this...
public class ViewModel : INotifyPropertyChanged
{
public ICommand DandCommand { get; set; }
public ViewModel()
{
DandCommand = new RelayCommand(ExecuteDandCommand, CanExecuteDandCommand);
}
private void ExecuteDandCommand(object obj)
{
if (obj != null)
{
IDataObject ido = obj as IDataObject;
if (ido != null)
{
var fileDrop = ido.GetData(DataFormats.FileDrop, true);
var filesOrDirectories = fileDrop as String[];
if (filesOrDirectories != null && filesOrDirectories.Length > 0)
{
foreach (string fullPath in filesOrDirectories)
{
if (Directory.Exists(fullPath))
{
Console.WriteLine(#"{0} is a directory", fullPath);
}
else if (File.Exists(fullPath))
{
Console.WriteLine(#"{0} is a file", fullPath);
}
else
{
Console.WriteLine(#"{0} is not a file and not a directory", fullPath);
}
}
}
}
}
}
private bool CanExecuteDandCommand(object obj)
{
return true;
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
This VM implements a command (called DandCommand) which will be fired by the attached behaviour (remember Step 1?). The 'juicy part' of the VM is the bit which dereferences the drag-and-drop payload. In this particular VM, the code dereferences the data and finds out if it is a file or a directory. It then prints a diagnostic to the console. You can change this part to load images, or internet links, or what-ever can be dropped.
Step 5: Wiring the data context
This is done by different developers in different ways (for industrial apps, lots of people like to use Prism and Unity, but that's ott for a simple how-to like this post). The most straight-forward approach is to change your View to look like this...
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
This code sets the window's data context to your VM so that the binding can take place.
Those steps give you a good starting point for MVVM and drag-and-drop and getting the whole thing to work. The big payback in using MVVM for these things is the clean separation and compartmentalisation that you get. I.e., the VM can be unit-tested without having to instantiate the WPF binding engine.

wpf - best practice of registering a DelegateCommand to a CompositeCommand

iv'e got a CompositeCommand exposed globally in my startup project
public static class Commands
{
public static readonly CompositeCommand DiceRolledCommand = new CompositeCommand();
}
in a ControlLibrary referenced by my startup project iv'e got a Control which has a DelegateCommand ,
each instance of this Control has to register it's Command with the globally exposed DiceRolledCommand.
what wold be the best practice of doing so :
here are 3 idea's of which the first 2 i don't like because they are a kinda of hack , where you take some programming component (dp) and alter it's use for your benefit , resulting in poor code and design .
1)
a regular decadency property of type CompositeCommand which will be set with DiceRolledCommand
and on it's CallBack register MyControl's DelegateCommand (OnDiceRolledCommand) .
public class MyControl : Control
{
public DelegateCommand<Tuple<int, int>> OnDiceRolledCommand { get; private set; }
public CompositeCommand GlobalDiceRolledCommand
{
get { return (CompositeCommand)GetValue(GlobalDiceRolledCommandProperty); }
set { SetValue(GlobalDiceRolledCommandProperty, value); }
}
public static readonly DependencyProperty GlobalDiceRolledCommandProperty =
DependencyProperty.Register("GlobalDiceRolledCommand", typeof(CompositeCommand), typeof(MyControl), new UIPropertyMetadata(null,GlobalDiceRolledCommandPropertyChanged));
private static void GlobalDiceRolledCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myControl= d as MyControl ;
var compoisteCommand = e.NewValue as CompositeCommand;
compoisteCommand.RegisterCommand(myControl.OnDiceRolledCommand);
}
}
<local:MyControl GlobalDiceRolledCommand="{x:Static local:Commands.DiceRolledCommand}"/>
i don't like this approach since it's a kind of manipulation where a Dependency Property is used has a Complex logical setter .
2) i could also do the same as in (1) using a third party class with an attached property which will register the OnDiceRolledCommand in an attached property's CallBack
public static class Commands
{
public static readonly CompositeCommand DiceRolledCommand = new CompositeCommand();
public static ICommand GetRegisterToDiceRolledCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(RegisterToDiceRolledCommandProperty);
}
public static void SetRegisterToDiceRolledCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(RegisterToDiceRolledCommandProperty, value);
}
public static readonly DependencyProperty RegisterToDiceRolledCommandProperty =
DependencyProperty.RegisterAttached("RegisterToDiceRolledCommand", typeof(ICommand), typeof(Commands), new UIPropertyMetadata(null,OnRegisterToDiceRolledCommandProperty);
private static void OnRegisterToDiceRolledCommandProperty(DependencyObject d , DependencyPropertyChangedEventArgs e)
{
var commandToRegister = e.newValue as DelegateCommand;
DiceRolledCommand.RegisterCommand(commandToRegister );
}
}
<local:MyContorl local:Commands.RegisterToDiceRolledCommand="{Binding OnDiceRolledCommand , RelativeSource={RelativeSource Self}}"/>
i also don't like this approach for the same reason as 1 ..
3) passing the composite command as a parameter to constructor , this approach is better since it keeps
the initializing logic in the constructor where it should be , i just can't figure out how to pass
an argument to a contractor through XAML , i'm not sure if it's even possible .
public class MyControl : Control
{
public MyControl(CompositeCommand globalDiceRolledCommand)
{
.........
globalDiceRolledCommand.Register(OnDiceRolledCommand);
}
}
<local:MyControl ..... >
Some how pass parameters to contractor in order to create the element in XAML
</local:MyControl>
to summarize :
A) any thoughts about (1) and (2) .
B) thoughts of how to accomplish 3 , and if it seems like good design .
C) Any good pattern of accomplishing this scenario.
thanks in advance .
Whenever I use Global Commands like that they are usually defined in either an Infrastructure class library which every library can reference. Or they are defined in a consuming core library that each module could reference directly.
I wrote a lot of this up in a Code Project article
Part 2 here

How can I find out why AutoFixture is throwing Kernel.OmitSpecimen exception

I am working on a fairly nested model which has some circular references. It also uses Entity Framework so all lists are ICollection<T>. To accommodate this I am configuring AutoFixture like so:
_fixture = new Fixture().Customize(new MultipleCustomization());
_fixture.Behaviors.Remove(new ThrowingRecursionBehavior());
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
When I try to create a type
_fixture.CreateAnonymous<Session>();
AutoFixture has a problem and throws the following error
System.InvalidCastException : Unable to cast object of type 'Ploeh.AutoFixture.Kernel.OmitSpecimen' to type 'The.Model.Language'
If I exclude the collection within Session of type Language, AutoFixture throws the same exception for another type in the graph.
Is there a way to extract more information from AutoFixture, e.g., the property that caused the error?
Why is AutoFixture trying to cast my type to OmitSpecimen and what in this process could have happened to prevent it from being cast?
I've created a gist for the stack trace here.
Update
I have managed to recreate the problem. Given this pair of objects
public class Session
{
public Language Language { get; set; }
}
public class Language
{
public ICollection<Session> Sessions { get; set; }
}
The call to _fixture.CreateAnonymous<Session>(); will throw the cast exception.
This works in a newer version of AutoFixture(for example 3.31.3).
This code does runs:
public class Session
{
public Language Language { get; set; }
}
public class Language
{
public ICollection<Session> Sessions { get; set; }
}
class Program
{
static void Main(string[] args)
{
var fixture = new Fixture();
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
var session = fixture.Create<Session>();
Debug.Assert(session != null, "Session should not be null");
}
}

Resources