CSLA 3.8 Beta 2 - PropertyStatus not working with MVVM Model

CSLA 3.8 Beta 2 - PropertyStatus not working with MVVM Model

Old forum URL: forums.lhotka.net/forums/t/7949.aspx


MAN-U posted on Thursday, November 05, 2009

Our team has gone through the sample codes for property status [PropertyStatus project] provided  @ http://www.lhotka.net/cslanet/download.aspx and it  is working as expected but the Property Status in MVVM sample [MVVMexperiment project] is failing  

 

In one of our applications, we are using MVVM model, ViewModels are inherited from ViewModel Base Class and corresponding business objects are tied to the Model. 

 

Whenever we are using PropertyStatus for the rule validation, we are getting the appropriate BrokenRulesCollection.  But we were not successful in populating the validation messages in the UI as shown in the non MVVM sample application [PropertyStatus Project].  

 While debugging the difference we could figure out from the non MVVM sample application with our application is, our code is not getting the handler for the below mentioned method in PropertyStatus.cs

 

private void source_PropertyChanged(object sender, PropertyChangedEventArgs e)

 

Instead of the above method, our code is navigating to the method in ExtendedBindingList.cs

 

protected virtual void Child_PropertyChanged(object sender, PropertyChangedEventArgs e)

 

Please help us in inplementing PropertyStatus in our MVVM application. Let us know if more information is required to understand the issue better.  Thanks

RockfordLhotka replied on Thursday, November 05, 2009

Please try Beta 3 to see if the problem still exists.

MAN-U replied on Friday, November 06, 2009

Tried with the latest version samples and the MVVM Experiment sample is not working.  It is giving a Null reference exception in the line Line: var targetMethod = target.GetType().GetMethod(methodName);   Method: private void CallMethod(object sender, EventArgs e)  and the File is: InvokeMethod.cs.

Debgging shows the error is triggering from the line

csla:InvokeMethod.TriggerEvent="Loaded" in Window1.xaml

StackTrace for the error is also provided below.  Please help

System.NullReferenceException was unhandled
  Message="Object reference not set to an instance of an object."
  Source="Csla"
  StackTrace:
       at Csla.Wpf.InvokeMethod.CallMethod(Object sender, EventArgs e) in C:\User Created Folder\Cambridge Soft\Inventory\CAG\3.8\cslacs\Csla\Wpf\InvokeMethod.cs:line 230
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
       at System.Windows.BroadcastEventHelper.BroadcastEvent(DependencyObject root, RoutedEvent routedEvent)
       at System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(Object root)
       at MS.Internal.LoadedOrUnloadedOperation.DoWork()
       at System.Windows.Media.MediaContext.FireLoadedPendingCallbacks()
       at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
       at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
       at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
       at System.Windows.Media.MediaContext.Resize(ICompositionTarget resizedCompositionTarget)
       at System.Windows.Interop.HwndTarget.OnResize()
       at System.Windows.Interop.HwndTarget.HandleMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.ShowWindow(HandleRef hWnd, Int32 nCmdShow)
       at System.Windows.Window.ShowHelper(Object booleanBox)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.DispatcherOperation.InvokeImpl()
       at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Threading.DispatcherOperation.Invoke()
       at System.Windows.Threading.Dispatcher.ProcessQueue()
       at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
       at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.Run()
       at System.Windows.Application.RunDispatcher(Object ignore)
       at System.Windows.Application.RunInternal(Window window)
       at System.Windows.Application.Run(Window window)
       at System.Windows.Application.Run()
       at MVVMexperiment.App.Main() in C:\User Created Folder\Cambridge Soft\Inventory\CSLA 3.8 Samples downloaded from Lhotka's site\CslaNet\cs\MVVMexperimentWpf\MVVMexperiment\obj\Debug\App.g.cs:line 0
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

 

RockfordLhotka replied on Friday, November 06, 2009

This is the WPF sample right?

 

You are correct, there should not be a call to InvokeMethod in the Window1 form declaration in the XAML. The XAML should read:

 

<Window x:Class="MVVMexperiment.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:this="clr-namespace:MVVMexperiment"

        xmlns:csla="clr-namespace:Csla.Wpf;assembly=Csla"

        Title="Window1" Height="480" Width="640">

 

What is strange is that this doesn’t fail on my machine, but does on yours. In any case, just remove that invalid line from the XAML and it should be fine.

MAN-U replied on Monday, November 09, 2009

Dear Rocky,

We have downloaded the CSLA framework 3.8 as well as the new samples, specifically the MVVMExperimentWpf sample. Also we made sure that the following line was removed from Windows1.xaml

csla:InvokeMethod.TriggerEvent="Loaded"

 When we enter an ID greater than 10 to break the corresponding business rule and click Process Item, it looks like validation is not being performed. Debugging shows that the BrokenRulesCollection is always empty. CheckRules methods in ValidationRules.cs are never been called.

Really appreciate it if you could take a look at it and let us know if we are missing something.

Thanks.

 

RockfordLhotka replied on Monday, November 09, 2009

I just ran the 3.8 release code and the range check works just fine. I entered 12 for an Id, tabbed off that control and the PropertyStatus control shows me that the value is in error.

sg11 replied on Monday, November 09, 2009

Rocky

When running this sample, the only way I could get rid of the follwing error in the designer for ListPage.xaml "Object reference not set to an instance of an object", was by changing

csla:PropertyStatus Margin="5" Property="{Binding Path=Model.Id}"
to
csla:PropertyStatus Margin="5" Property="{Binding Path=Id}"

in effect changing Model.Id to Id.

And either way, running the sample did not trigger a validation error. I was wondering if you might have a different set of goods on your machine.

Thanks.

RockfordLhotka replied on Monday, November 09, 2009

sg11:
Rocky When running this sample, the only way I could get rid of the follwing error in the designer for ListPage.xaml "Object reference not set to an instance of an object", was by changing csla:PropertyStatus Margin="5" Property="{Binding Path=Model.Id}" to csla:PropertyStatus Margin="5" Property="{Binding Path=Id}" in effect changing Model.Id to Id. And either way, running the sample did not trigger a validation error. I was wondering if you might have a different set of goods on your machine. Thanks.

I just compared the code I'm using to the code in the release and it is the same. Here's the release code from my repository:

http://www.lhotka.net/cslacvs/viewvc.cgi/samples/tags/V3-8-0/CslaNet/cs/MVVMexperimentWpf/MVVMexperiment/ListPage.xaml?revision=4413&view=markup

The controls are in a StackPanel, which has a DataContext pointing to the viewmodel object. Therefore the binding expressions on the individual controls must be Model.Id and Model.Name.

Please make sure you are using the release version of 3.8, not an earlier release. This project (in particular) was changing almost daily during the development process because (as you can guess from the name) this was my experimentation project for these features.

sg11 replied on Monday, November 09, 2009

Rocky

Thanks for the prompt reply. I'm dumbfounded by what the issue here is. I took in a shot in the dark by trying to figure out what might be different on your machine, and since I didn't have anything Silverlight related on my machine, I thought I'd install the following, which I did to no avail:

KB958017 - Rollup Hotfix for several issues in WPF designer Visual Studio 2008

Silverlight 3 Tools for VS 2008

Silverlight 3.

Kevin Fairclough replied on Tuesday, November 10, 2009

Works for me, Visual Studio 2008 (3.5 SP1)

MAN-U replied on Tuesday, November 10, 2009

Yes, Propertystatus  works for me in the MVVMExperimentWPF sample application.   Initially I entered values greater than 10 in the ID text box and no error messages displayed for me.  It took a while for me to figure out, first I have to select an item from the listbox and then change the value to a digit which is greater than 10.  In that case it is showing the error icon and the message as tooltip.

I have applied the same implementation in my application, and the issue I'm facing is - when the control comes to first time (before loading the page) to the SetSource Method of PropertyStatus.cs,  I'm getting the value of  Binding as {System.Windows.Data.BindingExpression} but 'Binding.DataItem' is null.  So it is throwing an error [ Null reference exception ].

I have added one more condition to the 'IF' statement in the SetSource method as shown below.

if ((binding != null) && (binding.DataItem != null))

and the PropertyStatus works as expected in the application. 

In my scenario, it is a popup window for a new dataentry screen

Is it advisible to add the condition (binding.DataItem != null) to the SetSource method of PropertyStatus? 

Is it a global scenario in a MVVM application that the Binding.DataItem is null when Binding has some value?  If yes, is that condition can be safely added to SetSource method?  Thanks

RockfordLhotka replied on Tuesday, November 10, 2009

I certainly hope you don’t try to use MVVMexperiment as an example of any good way to build an application!!

 

The title of the sample includes the word experiment. This sample is nothing more than a way to experiment with some of the basic ideas around MVVM and the use of InvokeMethod, Execute and ViewModel<T>.

 

It is absolutely not a complete app, and it certainly doesn’t illustrate how you should really build an app!

 

The most you should try to get out of MVVMexperiment is the basic usage of the new MVVM capabilities in 3.8.

 

Personally I never have regions of my forms enabled or visible if there’s no underlying datacontext. Why would you do that in a real app?

MAN-U replied on Wednesday, November 11, 2009

In my code, I'm assigning ViewModel for a View in one of my ViewModel.cs page

<< start --- portion of the code from my application>>

 public ILocationView View { get; set; }

 public void ApplyView(ILocationView view)
        {
            View = view;
            View.ViewModel = this;
        }

<< end --- portion of the code from my application>>

And the ViewModel is defined as a property in the code behind of xaml page

<< start --- portion of the code from my application>>

public ILocationActionViewModel ViewModel
        {
            get
            {
                return this.DataContext as ILocationActionViewModel;
            }
            set
            {
                this.DataContext = value;
            }
        }

<< end --- portion of the code from my application>>

So from the line 'View.ViewModel = this'; control goes to the 'Set' portion of the ViewModel Property.  And that triggers the event 'DataContextChanged'  in the constructor of Propertystatus.cs and calls the SetSource method. 

 public PropertyStatus()
    {
      DefaultStyleKey = typeof(PropertyStatus);
      BrokenRules = new ObservableCollection<BrokenRule>();

      DataContextChanged += (o, e) =>
        {
          SetSource();
          //SetSource(e.OldValue, e.NewValue);
        };

      Loaded += (o, e) => { UpdateState(); };
    }

And in the SetSource method while finding the binding using the below line

var binding = GetBindingExpression(PropertyProperty)

I'm getting 'binding' as notnull and binding.dataitem as null.  This happens only while loading the page.  

The issue identified was, while executing the line -  View.ViewModel = this;

'this.View' has value but 'this.View.ViewModel' is null. 

'this.View.ViewModel' has assigned the value only after triggering the 'DataContextChanged' event in PropertyStatus.cs and that calls the SetSource method.

DataContextChanged += (o, e) =>
        {
          SetSource();
          //SetSource(e.OldValue, e.NewValue);
        };

If I add the condition   'if ((binding != null) && (binding.DataItem != null))' in the SetSource Method of PropertyStatus.cs [ instead of  'if ((binding != null)' ], it works fine. 

Normal 0 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

Due to obvious reasons, I don’t want to change the code in PropertyStatus.cs.  It would be helpful if you can provide some suggestions to overcome the issue?  Or is it advisible to use the condition 'if ((binding != null) && (binding.DataItem != null))' in the SetSource method.   Thanks.



Fintanv replied on Friday, December 18, 2009

For what it's worth I am using Prism with my MVVM approach and also had to make this same change when upgrading to 3.8.

admin replied on Friday, December 18, 2009

Please try 3.8.2, as I believe the issue is resolved.

Copyright (c) Marimer LLC