Xamarin Forms iOS Validate Texbox and show error - mvvm

I've customized the Xamarin Forms Entry control for Android,
I'm using MVVM Validation for validating my Inputs via MVVM and generate a message for each form element.
Validator.AddRequiredRule(() => UserName, Messages.FieldCannotBlank);
Validator.AddRequiredRule(() => Password, Messages.FieldCannotBlank);
The customised entry I've used is an extended version of the Extended Entry by Xlabs. Here's the code for the Entry
public class ExtendedEntry : Entry
{
public ExtendedEntry()
{
BorderColor = Color.Default;
BGColorForRounded = Color.Default;
}
#region XAlign
/// <summary>
/// The XAlign property
/// </summary>
public static readonly BindableProperty XAlignProperty =
BindableProperty.Create(nameof(XAlign), typeof(TextAlignment), typeof(ExtendedEntry),
TextAlignment.Start);
/// <summary>
/// Gets or sets the X alignment of the text
/// </summary>
public TextAlignment XAlign
{
get { return (TextAlignment)GetValue(XAlignProperty); }
set { SetValue(XAlignProperty, value); }
}
#endregion
#region BGColorForRounded
public static BindableProperty BGColorForRoundedProperty =
BindableProperty.Create(nameof(BGColorForRounded), typeof(Color), typeof(ExtendedEntry), default(Color));
public Color BGColorForRounded
{
get { return (Color)GetValue(BGColorForRoundedProperty); }
set { SetValue(BGColorForRoundedProperty, value); }
}
#endregion
#region Padding
public static BindableProperty PaddingProperty =
BindableProperty.Create(nameof(Padding), typeof(Thickness), typeof(ExtendedEntry), default(Thickness), defaultBindingMode: BindingMode.OneWay);
public Thickness Padding
{
get { return (Thickness)GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
#endregion Padding
#region IsReadOnly
public static readonly BindableProperty IsReadOnlyProperty =
BindableProperty.Create("IsReadOnly", typeof(bool), typeof(ExtendedEntry), false);
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
#endregion
#region IsValid
public static readonly BindableProperty IsValidProperty =
BindableProperty.Create("IsValid", typeof(bool), typeof(ExtendedEntry), true);
public bool IsValid
{
get { return (bool)GetValue(IsValidProperty); }
set { SetValue(IsValidProperty, value); }
}
#endregion
#region ErrorHint
public static readonly BindableProperty ErrorHintProperty =
BindableProperty.Create("ErrorHint", typeof(string), typeof(ExtendedEntry), "");
public string ErrorHint
{
get { return (string)GetValue(ErrorHintProperty); }
set { SetValue(ErrorHintProperty, value); }
}
#endregion
#region PlaceholderTextColor
/// <summary>
/// The PlaceholderTextColor property
/// </summary>
public static readonly BindableProperty PlaceholderTextColorProperty =
BindableProperty.Create("PlaceholderTextColor", typeof(Color), typeof(ExtendedEntry), Color.Default);
/// <summary>
/// Sets color for placeholder text
/// </summary>
public Color PlaceholderTextColor
{
get { return (Color)GetValue(PlaceholderTextColorProperty); }
set { SetValue(PlaceholderTextColorProperty, value); }
}
#endregion
#region HasBorder
/// <summary>
/// The HasBorder property
/// </summary>
public static readonly BindableProperty HasBorderProperty =
BindableProperty.Create("HasBorder", typeof(bool), typeof(ExtendedEntry), true);
/// <summary>
/// Gets or sets if the border should be shown or not
/// </summary>
public bool HasBorder
{
get { return (bool)GetValue(HasBorderProperty); }
set { SetValue(HasBorderProperty, value); }
}
#endregion
#region BorderRadius
public int BorderRadius
{
get { return (int)GetValue(BorderRadiusProperty); }
set { SetValue(BorderRadiusProperty, value); }
}
// Using a DependencyProperty as the backing store for BorderRadius. This enables animation, styling, binding, etc...
public static readonly BindableProperty BorderRadiusProperty =
BindableProperty.Create("BorderRadius", typeof(int), typeof(ExtendedEntry), 0);
#endregion
#region BorderColor
/// <summary>
/// The Border Color Property
/// </summary>
public static readonly BindableProperty BorderColorProperty =
BindableProperty.Create("BorderColor", typeof(Color), typeof(ExtendedEntry), default(Color));
/// <summary>
/// Gets or sets the border color
/// </summary>
public Color BorderColor
{
get { return (Color)GetValue(BorderColorProperty); }
set { SetValue(BorderColorProperty, value); }
}
#endregion
}
Whenever a button is pressed, I call the Validators ValidateAll method to validate all my fields
var result = Validator.ValidateAll();
if (!result.IsValid)
{
App.Current.MainPage.DisplayAlert("Error", "The forms has errors, please review the errors and fix them.", "Ok");
}
Errors = result.AsDictionary();
Errors is another property of the Viewmodel which is basically a dictionary which will hold a list of key-value pairs of property names and errors after validation. I map this value to the ErrorHint property of my ExtendedEntry in Xaml
<controls:ExtendedEntry ErrorHint="{Binding Errors[UserName]}"
IsValid="{Binding Errors[UserName], Converter={StaticResource DictBool},
Mode=TwoWay}"
Placeholder="sallysmith#gmail.com"
Style="{DynamicResource WhiteEntryStandard}"
Text="{Binding UserName}" />
And to finish off, this is the implementation for Android
private void SetValidityAndHint(ExtendedEntry view)
{
if (!view.IsValid)
{
if (!string.IsNullOrEmpty(view.ErrorHint))
{
Control.Error = view.ErrorHint;
}
}
}
This works fine for Android. But I haven't been able to find a solution for iOS. It looks like iOS doesn't have any kind of error property at all. Any pointers anyone??

Related

Create Wizard with MVVM Pattern - Databinding and GUI Update not working

I am creating a Wizard for automatic Report generating. Therefore the user enters a couple of Issues to the Mainwindow and after he finished, he can create an automatically filled report by clicking a button. Also he need to switch between the entered Issuses (Therefore I put the issues to a list of the Type "Compliant".
The MainWindow contains different controls, in which the user can enter some information.
All controls are binded to the Model like this way (example for a textbox):
Text="{Binding Path=SingleCompliant.Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
"SingleCompliant" is an object of the ViewModel of the type "Compliant" (part of the Model), which contains all attributes needed for one Issue.
When I load the Application for the first time, everything works fine.
But when I click on "SaveCompliantAndNext", the binding between "SingleCompliant" Object gets lost and the GUI is not updating. In this Method (raised by a command) I create a new SingleCompliant Object.
What do I need to do for getting a new Object with an empty gui, so the user can continue entereing the next Issue?
This is the ViewModel with implemented "PropertyChanged" Handling:
public class Compliant_ViewModel : ObservableCollection<Compliant> //INotifyPropertyChanged
{
/// <summary>
/// MainWindow Controls are binded to Attributes of this object
/// </summary>
private Compliant _SingleCompliant;
public ObservableCollection<Compliant> CompliantListReport
{
get { return _CompliantListReport; }
private set { _CompliantListReport = value; }
}
/// <summary>
/// Beandstandungs-Objekt
/// </summary>
public Compliant SingleCompliant
{
get { return _SingleCompliant; }
set
{ _SingleCompliant = value;
OnPropertyChanged("SingleCompliant");
}
}
/// <summary>
/// Load next Compliant to the GUI
/// </summary>
public NextCompliant_Command NextCompliant_command { get; private set; }
/// <summary>
/// Load previous Compliant to the GUI
/// </summary>
public PreviousCompliant_Command PreviousCompliant_Command { get; private set; }
/// <summary>
/// Constructor
/// </summary>
public Compliant_ViewModel()
{
SingleCompliant = new Compliant();
CompliantListReport = new ObservableCollection<Compliant>();
NextCompliant_command = new NextCompliant_Command(SaveCompliantAndNext);
PreviousCompliant_Command = new PreviousCompliant_Command(LoadPreviousCompliant);
CreateReport_Command = new CreateReport_Command(CreateReport);
}
public void SaveCompliantAndNext()
{
CompliantListReport.Add(SingleCompliant);
// >>>>> Not working - databinding get lost and gui not updating
SingleCompliant = new Compliant();
}
public void LoadPreviousCompliant()
{
if (this.SingleCompliant.CompliantID > 0)
{ this.SingleCompliant = this.CompliantListReport[this.SingleCompliant.CompliantID - 1]; }
else
{ this.SingleCompliant = this.CompliantListReport[0]; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyname)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{ handler(this, new PropertyChangedEventArgs(propertyname)); }
}
}
This is the Model:
public class Compliant : INotifyPropertyChanged
{
public string _Text;
public string Text
{
get { return _Text; }
private set
{
_Text = value;
OnPropertyChanged("Text");
}
}
#region Konstruktoren
public Compliant()
{ }
#region Interface
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyname)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyname));
}
}
#endregion Interface
}
XAML:
Example for one Textbox:
<TextBox Text="{Binding Path=SingleCompliant.Text, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" x:Name="Text" />
XAML Buttons to switch between the Compliants (Issues):
<!--Previous Compliant (Issue)-->
<Button x:Name="BtnBack_Compliant" Content="{DynamicResource Back}" Command="{Binding PreviousCompliant_Command}"/>
<!--Next Compliant (Issue)-->
<Button x:Name="BtnForeward_Compliant" Content="{DynamicResource Foreward}" Command="{Binding NextCompliant_command}" />
What do I make wrong?

WPF MVVM Command CanExecute, reevaluates only at focus change

Refactoring an MVVM project in WPF, I'm trying to get rid of what seems a common problem between MVVM pattern users.
I have view, who's DataContext is MyViewModel. Here is a button, bound with a Command that implements both Execute and CanExecute.
XAML:
<Button Command="{Binding ConnectCommand}"/>
MyViewModel exposes ConnectCommand:
public ICommand ConnectCommand
{
get { return new DelegateCommand(() => Connect(), () => IsConnectEnabled); }
}
(at the end the definition of DelegateCommand I'm using)
MyViewModel also exposes the property IsConnectEnabled, used in the CanExecute part of the Command:
public bool IsConnectEnabled
{
get
{
return (isDisconnected && null!=selectedDevice && 0<selectedDevice.Length);
}
}
MyViewModel class implements the INotifyPropertyChanged interface
public class MyViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region rest of the class
}
The CanExecute part of the command is only evaluated on a change of focus in the application (ie, whatever click I do). I know that the UpdateSourceTrigger is by default set to PropertyChanged, therefore my current solution, is to manually raise a PropertyChanged event in a few places in the code. But I want to do better and have this activity done automatically whenever the value of IsConnectEnabled changes.
Does the WPF and the MVVM pattern offer a solution for this issue?
For completeness, follows the complete ICommand implementation I'm using, DelegateCommand:
/// <summary>
/// This class allows delegating the commanding logic to methods passed as parameters,
/// and enables a View to bind commands to objects that are not part of the element tree.
/// </summary>
public class DelegateCommand : ICommand
{
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action executeMethod)
: this(executeMethod, null, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
}
#region Public Methods
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute()
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod();
}
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute()
{
if (_executeMethod != null)
{
_executeMethod();
}
}
/// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
}
/// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
/// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
}
#endregion
#region ICommand Members
/// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute();
}
void ICommand.Execute(object parameter)
{
Execute();
}
#endregion
#region Data
private readonly Action _executeMethod = null;
private readonly Func<bool> _canExecuteMethod = null;
private bool _isAutomaticRequeryDisabled = false;
private List<WeakReference> _canExecuteChangedHandlers;
#endregion
}
/// <summary>
/// This class allows delegating the commanding logic to methods passed as parameters,
/// and enables a View to bind commands to objects that are not part of the element tree.
/// </summary>
/// <typeparam name="T">Type of the parameter passed to the delegates</typeparam>
public class DelegateCommand<T> : ICommand
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<T> executeMethod)
: this(executeMethod, null, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null)
{
throw new ArgumentNullException("executeMethod");
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
}
#endregion
#region Public Methods
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(T parameter)
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod(parameter);
}
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute(T parameter)
{
if (_executeMethod != null)
{
_executeMethod(parameter);
}
}
/// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
/// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
}
/// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled
{
get
{
return _isAutomaticRequeryDisabled;
}
set
{
if (_isAutomaticRequeryDisabled != value)
{
if (value)
{
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
}
else
{
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
}
_isAutomaticRequeryDisabled = value;
}
}
}
#endregion
#region ICommand Members
/// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested += value;
}
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
}
remove
{
if (!_isAutomaticRequeryDisabled)
{
CommandManager.RequerySuggested -= value;
}
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
}
bool ICommand.CanExecute(object parameter)
{
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if (parameter == null &&
typeof(T).IsValueType)
{
return (_canExecuteMethod == null);
}
return CanExecute((T)parameter);
}
void ICommand.Execute(object parameter)
{
Execute((T)parameter);
}
#endregion
#region Data
private readonly Action<T> _executeMethod = null;
private readonly Func<T, bool> _canExecuteMethod = null;
private bool _isAutomaticRequeryDisabled = false;
private List<WeakReference> _canExecuteChangedHandlers;
#endregion
}
/// <summary>
/// This class contains methods for the CommandManager that help avoid memory leaks by
/// using weak references.
/// </summary>
internal class CommandManagerHelper
{
internal static void CallWeakReferenceHandlers(List<WeakReference> handlers)
{
if (handlers != null)
{
// Take a snapshot of the handlers before we call out to them since the handlers
// could cause the array to me modified while we are reading it.
EventHandler[] callees = new EventHandler[handlers.Count];
int count = 0;
for (int i = handlers.Count - 1; i >= 0; i--)
{
WeakReference reference = handlers[i];
EventHandler handler = reference.Target as EventHandler;
if (handler == null)
{
// Clean up old handlers that have been collected
handlers.RemoveAt(i);
}
else
{
callees[count] = handler;
count++;
}
}
// Call the handlers that we snapshotted
for (int i = 0; i < count; i++)
{
EventHandler handler = callees[i];
handler(null, EventArgs.Empty);
}
}
}
internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested += handler;
}
}
}
}
internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers)
{
if (handlers != null)
{
foreach (WeakReference handlerRef in handlers)
{
EventHandler handler = handlerRef.Target as EventHandler;
if (handler != null)
{
CommandManager.RequerySuggested -= handler;
}
}
}
}
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler)
{
AddWeakReferenceHandler(ref handlers, handler, -1);
}
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize)
{
if (handlers == null)
{
handlers = (defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>());
}
handlers.Add(new WeakReference(handler));
}
internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler)
{
if (handlers != null)
{
for (int i = handlers.Count - 1; i >= 0; i--)
{
WeakReference reference = handlers[i];
EventHandler existingHandler = reference.Target as EventHandler;
if ((existingHandler == null) || (existingHandler == handler))
{
// Clean up old handlers that have been collected
// in addition to the handler that is to be removed.
handlers.RemoveAt(i);
}
}
}
}
}
}
This is an old buggy behaviour, at least in my WPF experience.
I have found that the MvvmLight implementation of RelayCommand (GalaSoft.MvvmLight.CommandWpf.RelayCommand) seems to solve this issue.
Notice that they even create a WPF specific implementation (!) that apparently is targeted to correct this weirdness.

this.VerifyPropertyName(propertyName); in OnPropertyChanged() always returns null

I have a xaml code as follows:
On MouseLeftButtonDown i redirect it to viewModel where the color GenerateGlowEffect must change. This is not reflected. It always returns null for this.PropertyChanged
XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:telerikDocking="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking"
xmlns:Telerik_Windows_Controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls"
xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="TabItemContents.MapDetail"
mc:Ignorable="d" Width="Auto" Height="430.333">
<Grid x:Name="LayoutRoot" Background="{StaticResource TabControlActiveAreaColor}" Height="430.333" VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="192.833"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle IsHitTestVisible="True" x:Name="Rectangle_Generate" Margin="25.334,70.167,0,65.333" Cursor="{DynamicResource HandCursor}" RadiusX="10" RadiusY="10" HorizontalAlignment="Left" Width="88.5" StrokeThickness="1.5" d:LayoutOverrides="HorizontalAlignment" MouseLeftButtonDown="Rectangle_Generate_MouseLeftButtonDown" >
<Rectangle.Fill>
<SolidColorBrush Color="{DynamicResource RectangleColor}"/>
</Rectangle.Fill>
<Rectangle.Effect >
<DropShadowEffect RenderingBias="Quality" BlurRadius="{DynamicResource BlurRadius}" ShadowDepth="0" Color="{Binding GenerateGlowEffect}" />
</Rectangle.Effect>
</Rectangle>
</Grid>
CODEBEHIND:
public partial class MapDetail : UserControl
{
ViewModel ViewModelObject;
public MapDetail()
{
InitializeComponent();
ViewModelObject= new ViewModelObject((IUnityContainer)Application.Current.Properties["UnityContainer"]);
}
private void Rectangle_Generate_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ViewModelObject.SetColor();
}
}
VIEWMODEL:
public class ViewModel : ViewModelBase
{
private IUnityContainer _unityContainer;
private ILogger _logger;
private Model model;
private string _generateGlowEffect;
public ViewModel(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
try
{
model = new Model(unityContainer);
}
catch (Exception ex)
{
throw ex;
}
}
public void SetColor()
{
GenerateGlowEffect = "White";
}
public string GenerateGlowEffect
{
get { return _generateGlowEffect; }
set {
_generateGlowEffect = value;
OnPropertyChanged("GenerateGlowEffect");
}
}
}
}
public string GenerateGlowEffect
{
get { return _generateGlowEffect; }
set {
_generateGlowEffect = value;
OnPropertyChanged("GenerateGlowEffect");
}
}
ViewModelBase:
public class ViewModelBase : INotifyPropertyChanged, IDisposable
{
#region Constructor
protected ViewModelBase()
{
}
#endregion // Constructor
#region DisplayName
/// <summary>
/// Returns the user-friendly name of this object.
/// Child classes can set this property to a new value,
/// or override it to determine the value on-demand.
/// </summary>
public virtual string DisplayName { get; protected set; }
#endregion // DisplayName
#region Debugging Aides
/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
[DebuggerStepThrough]
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)
{
string msg = "Invalid property name: " + propertyName;
if (this.ThrowOnInvalidPropertyName)
throw new Exception(msg);
else
Debug.Fail(msg);
}
}
/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail() is used
/// when an invalid property name is passed to the VerifyPropertyName method.
/// The default value is false, but subclasses used by unit tests might
/// override this property's getter to return true.
/// </summary>
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }
#endregion // Debugging Aides
#region INotifyPropertyChanged Members
/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
#endregion // INotifyPropertyChanged Members
#region IDisposable Members
/// <summary>
/// Invoked when this object is being removed from the application
/// and will be subject to garbage collection.
/// </summary>
public void Dispose()
{
this.OnDispose();
}
/// <summary>
/// Child classes can override this method to perform
/// clean-up logic, such as removing event handlers.
/// </summary>
protected virtual void OnDispose()
{
}
#endregion // IDisposable Members
}
}
If this.PropertyChanged is null it means that your XAML is not bound against the property.
You need to set the DataContext otherwise the WPF engine doesn't know what to bind against.
public MapDetail()
{
InitializeComponent();
this.ViewModelObject= new VViewModelObject((IUnityContainer)Application.Current.Properties["UnityContainer"]);
this.DataContext = this.ViewModelObject;
}

Unit test Entity Framework using moq

I'm using entity framework and trying to unit test my data services which are using EF.
I'm not using repository and unit of work patterns.
I tried the following approach to mock the context and DbSet:
private static Mock<IEFModel> context;
private static Mock<IDbSet<CountryCode>> idbSet;
[ClassInitialize]
public static void Initialize(TestContext testContext)
{
context = new Mock<IEFModel>();
idbSet = new Mock<IDbSet<CountryCode>>();
context.Setup(c => c.CountryCodes).Returns(idbSet.Object);
}
I get null "Object reference not set to an instance of an object" error for idbSet "Local".
Is there any way to mock idbSet like this?
Thanks
I worked it out like this:
Created two classes named DbSetMock:
public class DbSetMock<T> : IDbSet<T>
where T : class
{
#region Fields
/// <summary>The _container.</summary>
private readonly IList<T> _container = new List<T>();
#endregion
#region Public Properties
/// <summary>Gets the element type.</summary>
public Type ElementType
{
get
{
return typeof(T);
}
}
/// <summary>Gets the expression.</summary>
public Expression Expression
{
get
{
return this._container.AsQueryable().Expression;
}
}
/// <summary>Gets the local.</summary>
public ObservableCollection<T> Local
{
get
{
return new ObservableCollection<T>(this._container);
}
}
/// <summary>Gets the provider.</summary>
public IQueryProvider Provider
{
get
{
return this._container.AsQueryable().Provider;
}
}
#endregion
#region Public Methods and Operators
/// <summary>The add.</summary>
/// <param name="entity">The entity.</param>
/// <returns>The <see cref="T"/>.</returns>
public T Add(T entity)
{
this._container.Add(entity);
return entity;
}
/// <summary>The attach.</summary>
/// <param name="entity">The entity.</param>
/// <returns>The <see cref="T"/>.</returns>
public T Attach(T entity)
{
this._container.Add(entity);
return entity;
}
/// <summary>The create.</summary>
/// <typeparam name="TDerivedEntity"></typeparam>
/// <returns>The <see cref="TDerivedEntity"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
throw new NotImplementedException();
}
/// <summary>The create.</summary>
/// <returns>The <see cref="T"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public T Create()
{
throw new NotImplementedException();
}
/// <summary>The find.</summary>
/// <param name="keyValues">The key values.</param>
/// <returns>The <see cref="T"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public T Find(params object[] keyValues)
{
throw new NotImplementedException();
}
/// <summary>The get enumerator.</summary>
/// <returns>The <see cref="IEnumerator"/>.</returns>
public IEnumerator<T> GetEnumerator()
{
return this._container.GetEnumerator();
}
/// <summary>The remove.</summary>
/// <param name="entity">The entity.</param>
/// <returns>The <see cref="T"/>.</returns>
public T Remove(T entity)
{
this._container.Remove(entity);
return entity;
}
#endregion
#region Explicit Interface Methods
/// <summary>The get enumerator.</summary>
/// <returns>The <see cref="IEnumerator"/>.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this._container.GetEnumerator();
}
#endregion
}
and EFModelMock:
public class EFModelMock : IEFModel
{
#region Fields
/// <summary>The country codes.</summary>
private IDbSet<CountryCode> countryCodes;
#endregion
#region Public Properties
/// <summary>Gets the country codes.</summary>
public IDbSet<CountryCode> CountryCodes
{
get
{
this.CreateCountryCodes();
return this.countryCodes;
}
}
#endregion
#region Public Methods and Operators
/// <summary>The commit.</summary>
/// <exception cref="NotImplementedException"></exception>
public void Commit()
{
throw new NotImplementedException();
}
/// <summary>The set.</summary>
/// <typeparam name="T"></typeparam>
/// <returns>The <see cref="IDbSet"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public IDbSet<T> Set<T>() where T : class
{
throw new NotImplementedException();
}
#endregion
#region Methods
/// <summary>The create country codes.</summary>
private void CreateCountryCodes()
{
if (this.countryCodes == null)
{
this.countryCodes = new DbSetMock<CountryCode>();
this.countryCodes.Add(
new CountryCode { CountryName = "Australia", DisplayLevel = 2, TelephoneCode = "61" });
}
}
#endregion
}
Then tested like this:
[TestClass]
public class CountryCodeServiceTest
{
#region Static Fields
/// <summary>The context.</summary>
private static IEFModel context;
#endregion
#region Public Methods and Operators
/// <summary>The initialize.</summary>
/// <param name="testContext">The test context.</param>
[ClassInitialize]
public static void Initialize(TestContext testContext)
{
context = new EFModelMock();
}
/// <summary>The country code service get country codes returns correct data.</summary>
[TestMethod]
public void CountryCodeServiceGetCountryCodesReturnsCorrectData()
{
// Arrange
var target = new CountryCodeService(context);
var countryName = "Australia";
var expected = context.CountryCodes.ToList();
// Act
var actual = target.GetCountryCodes();
// Assert
Assert.IsNotNull(actual);
Assert.AreEqual(actual.FirstOrDefault(a => a.CountryName == countryName).PhoneCode, expected.FirstOrDefault(a => a.CountryName == countryName).TelephoneCode);
}
You have to set up the Local property of your idbSet mock.
For example:
idbSet = new Mock<IDbSet<CountryCode>>();
var col = new ObservableCollection<CountryCode>();
idbSet.SetupGet(x => x.Local).Returns(col);
I had been using a method to create my mock sets like this:
public static Mock<IDbSet<T>> CreateMockSet<T>(IQueryable<T> data) where T : class
{
var mockSet = new Mock<IDbSet<T>>();
mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
return mockSet;
}
I merely added this line:
mockSet.Setup(x => x.Local).Returns(new ObservableCollection<T>());
before the return statement and it solved my problems.
Many of my queries look like this:
var myset = context.EntitySetName.Local.SingleOrDefault(x=>x.something==something)
??
context.SingleOrDefault(x=>x.something==something);
So I just need Local to not be null so that it doesn't throw a null reference exception.

PropertyChangedEventHandler is null in FirePropertyChanged

I have a viewmodel named EmployeeViewModel which is inherited from ViewModelBase. here is the implementation of ViewModelBase.
public event PropertyChangedEventHandler PropertyChanged;
public void FirePropertyChanged(string propertyname)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyname));
}
public void FirePropertyChanged<TValue>(Expression<Func<TValue>> propertySelector)
{
if (PropertyChanged != null)
{
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(memberExpression.Member.Name));
}
}
}
My EmployeeViewModel has a property name GridResults, which is bound to the Grid on View, here is the property definition.
public PagedCollectionView GridResults
{
get { return _gridResults; }
set
{
_gridResults = value;
FirePropertyChanged(()=>GridResults);
}
}
Now when i set value of GridResults somewhere in the code in EmployeeViewModel, it fires the property change event and goes into
FirePropertyChanged(Expression> propertySelector)
but inside that method its PropertyChangedEventHandler always remain null and it prevents the complete execution of method. Ultimately my Grid on View remain unnoticed that its underlying itemsource has been changed.
Am i missing something??
Thankx in advance
-K9
Did your ViewModelBase really implement INotifyPropertyChanged?
if yes, please try the FirePropertyChanged with string parameter.
public PagedCollectionView GridResults
{
get { return _gridResults; }
set
{
_gridResults = value;
FirePropertyChanged("GridResults");
}
}
btw here is the INPCBase class i use:
/// <summary>
/// Basisklasse für INotifyPropertyChanged.
/// </summary>
public class INPCBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notify mittels PropertyInfo. HINWEIS: diese Variante ist ungefähr 3x langsamer wie
/// <see cref="NotifyPropertyChanged(string)"/> bzw. <see cref="NotifyPropertyChanged(System.ComponentModel.PropertyChangedEventArgs)"/>.
/// </summary>
/// <example>
/// <code>
/// public string InfoMessage
/// {
/// get {return this.infomessage;}
/// set
/// {
/// this.infomessage = value;
/// this.NotifyPropertyChanged(()=> this.InfoMessage);
/// }
/// }
/// </code>
/// </example>
/// <typeparam name="T"></typeparam>
/// <param name="property"></param>
protected void NotifyPropertyChanged<T>(Expression<Func<T>> property)
{
var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
}
this.VerifyPropertyName(propertyInfo.Name);
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyInfo.Name));
}
/// <summary>
/// Notify using pre-made PropertyChangedEventArgs
/// </summary>
/// <param name="args"></param>
protected void NotifyPropertyChanged(PropertyChangedEventArgs args)
{
this.VerifyPropertyName(args.PropertyName);
var handler = PropertyChanged;
if (handler != null)
{
handler(this, args);
}
}
/// <summary>
/// Notify using String property name
/// </summary>
protected void NotifyPropertyChanged(String propertyName)
{
this.VerifyPropertyName(propertyName);
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Debugging Aides
/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
[DebuggerStepThrough]
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)
return;
var msg = "Invalid property name: " + propertyName;
if (this.ThrowOnInvalidPropertyName)
throw new Exception(msg);
Debug.Fail(msg);
}
/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail() is used
/// when an invalid property name is passed to the VerifyPropertyName method.
/// The default value is false, but subclasses used by unit tests might
/// override this property's getter to return true.
/// </summary>
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }
#endregion // Debugging Aides
}