Use with Silverlight project

Aug 14, 2009 at 10:35 PM

Hi, Is this project ready to be used with Silverlight? I was confused going through http://silverlight.net/forums/t/93085.aspx which mentions about an aggregate on an observable collection. But when I tried to add the binaries to my SL project, I got a "Not built against Silverlight runtime error".

Can you please advise.

Thanks Vinay

Coordinator
Aug 15, 2009 at 12:25 AM

Hi Vinay,

Unfortunately Obtics has not been ensured yet against silverlight.

The binaries have been compiled against the standard .Net libraries. I am not a Silverlight expert but I know that it uses its own set of runtime libraries. (its own System, System.Core etc. assemblies) and the Obtics sources will need to be compiled against those for it to be usable with Silverlight. I haven't done it yet and I expect there will be some incompatibilities but I don't know how bad they will be.

If someone would like to do this I would be very interested.

Regs,

Thomas.

Coordinator
Aug 23, 2009 at 2:11 AM

The latest source checkin (26133) has a project Obtics_Silverlight that builds a working Obtics library for Silverlight.

The help of BindingHelper_Silverlight is needed for convenient binding to IValueProvider properties. Checkout ObticsUnitTestRunner_SilverLight for an example.

Regs,

Thomas.

Aug 26, 2009 at 9:13 PM

I downloaded the latest binaries and followed instructions mentioned in http://silverlight.net/forums/t/93085.aspx 

I basically need to track sum of a particular property within an object which implments INOtifyChange. However I get the following compilation error

Error 9 The call is ambiguous between the following methods or properties: 'System.Linq.Enumerable.Sum<SLSocketsApp1.CustOrderDecorator>(System.Collections.Generic.IEnumerable<SLSocketsApp1.CustOrderDecorator>, System.Func<SLSocketsApp1.CustOrderDecorator,decimal?>)' and 'Obtics.Collections.ObservableEnumerable.Sum<SLSocketsApp1.CustOrderDecorator>(System.Collections.Generic.IEnumerable<SLSocketsApp1.CustOrderDecorator>, System.Func<SLSocketsApp1.CustOrderDecorator,decimal?>)' 

Can you please provide me a sample. I tried the chm help on your download site but that seems to be broken since it does nt show the articles on the right panel.

Your help is very appreciated.

Thanks

VInay

Coordinator
Aug 27, 2009 at 12:22 AM

Hi Vinay,

When using ExpressionObserver with Linq statements don't include the Obtics.Collections namespace in your source code. Extension methods in the ObservableEnumerable will conflict with the ones in System.Linq.Enumerable. ExpressionObserver will do the mapping of System.Linq.Enumerable methods to Obtics.Collections.ObservableEnumerable methods.

Also you will need the 'Concrete' extension method from the BindingHelper_Silverlight library. This is (I think, with my limited Silverlight knowledge) because Silverlight can not resolve Interface properties explicitly. The Code behind will become like:

using System.Linq;
using Obtics;
using Obtics.Values;
//using Obtics.Collections; Not!

public partial class Test : UserControl
{
    ObservableCollection<TElement> _vals;

    public IValueProvider<TSomefield> Total 
    {
        get
        {
            return ExpressionObserver.Execute( ()=> _vals.Sum(p=>p.somefield) ).Concrete();
        }
    }
}
Aug 27, 2009 at 2:38 PM
Edited Aug 27, 2009 at 3:09 PM

The snippet you provided above does not seem to provide lambda expressions or bind to the text box. I am binding using the following

<TextBlock Canvas.Top="80" x:Name="total" Text="{Binding Path=Total.Value}"/>

Following the sample provided in the RegexTool within your source, I tried to add a reference in my xaml and bind using the following

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

<

</font></font><font size="2" color="#0000ff">

 

</font>

TextBlock x:Name="total" Text="{Binding Path=Total.(ov:IValueProvider.Value), UpdateSourceTrigger=PropertyChanged}"/>

But this gives me a runtime error of invalid element found. I am not sure if the ExpressionObserver.Execute is being binded properly to the control. Can you give me a sample where by an aggregated value is being binded to a textblock. The reason I am trying this software is because I want to be able to do more complex lamda statements following ObservableCollections. I could use CLINQ but this seems like a more promising version.

Any help will be appreciated. Also you compiled help file seems to be broken.

Thanks

Vinay

Coordinator
Aug 27, 2009 at 6:26 PM

Hi Vinay,

The snipped provided here is just the code behind. You should be able to bind to it in silverlight using code like:

<TextBlock Canvas.Top="80" x:Name="total" Text="{Binding Path=Total.Value}"/>

Explicit property reference doesn't seem to work in Silverlight. (The Text="{Binding Path=Total.(ov:IValueProvider.Value)" version). What is needed is the Concrete() extension method. It creates an adapter for the IValueProvider interface that is of a concrete and public type. The Concrete() method is used in the example snipped.

The bit: ()=> _vals.Sum(p=>p.somefield) in the snipped is a lambda expression. Just one that doesn't take any arguments. The snipped could also be written as (and would actually be better but slightly more code) :

using System.Linq;
using Obtics;
using Obtics.Values;
//using Obtics.Collections; Not!

public partial class Test : UserControl
{
    ObservableCollection<TElement> _vals;

    public IValueProvider<TSomefield> Total 
    {
        get
        {
            return ExpressionObserver.Execute( _vals, c => c.Sum(p=>p.somefield) ).Concrete();
        }
    }
}

The project ObticsUnitTestRunner_SilverLight in the solution (source files) builds a silverlight application. In the ViewModel class (in ViewModel.cs) is a property 'PassedCount' and 'FailedCount'. These properties do not use in-place compilation but pre-compile the lambda expressions. The principle is the same though. The last method executed to yield the result is Concrete() and the Xaml (MainPage.Xaml) binds to the properties.

So for the PassedCount property (pre-compiled):

#region PassedCount ; total number of visible test methods that have passed during their last run.
        public IValueProvider<int> PassedCount
        { get { return _PassedCountF(this).Async().Concrete(); } }

        static Func<ViewModel, IValueProvider<int>> _PassedCountF =
            ExpressionObserver.Compile(
                (ViewModel t) =>
                    t.VisibleMethods
                        .Where(m => t.Context.GetTestMethodResult(m.TestMethod).Value.Type == TestResultType.Success)
                        .Count()
            );
#endregion

Xaml (ViewModel is the DataContext):

<ContentControl Margin="0,12,12,12"  Content="{Binding Path=PassedCount.Value}" />

What do you mean by the help file seems broken? Undoubtedly many things are still missing but it does work. You need a viewer for it (an HTML help 1x viewer) and it may be possible that windows blocks the helpfile (because you downloaded it from the internet). You may need to right-mouse-click on it, select properties and click 'Unblock' on the 'General' tab.

Hope this helps.

Regs,

THomas.

 

 

 

 

 

 

 

Aug 28, 2009 at 3:26 PM

Thomas, Thanks a lot for the response. Since I needed the option urgently, I created another object implementing INotifychanged. The helpfile being broken, I meant that I am not able to see the details of the indeces. It may be some settings on my PC. I will try this in detail because it may turn out to be very useful in circumstances where one wants to bind multiple controls out of a single observable collection. E.g. I need to implement filter options on an observablecollection which is binded to a datagrid, by using distinct feature for each property (or column) in the grid. Also the observable collection implements a real time listening and binding, so I believe obtics supports that. Thanks for the help on this

Aug 28, 2009 at 4:39 PM

Thomas, I tried your suggested approach again. I have a simple Page with just a textblock with an observablecollection which updates every second based on a timer. I am not using using an MVVM model. Its a very simple bind to control approach.

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

<

</font></font><font size="2" color="#0000ff">

 

</font>

TextBlock Text="Status" Foreground="#FF14517B" Margin="5,0,0,0"></TextBlock>

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

<

</font></font><font size="2" color="#0000ff">

 

</font>

TextBlock x:Name="total" Text="{Binding Path=Total.Value}"/>

 

public IValueProvider<int> Total
        {
            get
            {
                return ExpressionObserver.Execute(custOrdersList, c => c.Sum(p => p.ExecSharesCum)).Concrete();
            }
        }

However I dont see the textblock display any data. Should i be doing something else. I will appreciate if you could forward me a quick sample displaying the same.

Thanks again for all the help

Coordinator
Aug 29, 2009 at 12:59 AM

Hi Vinay,

Find an example project here: http://obtics.codeplex.com/Wiki/View.aspx?title=Poc

It is almost the same. For simplicity it takes the sum over an ObservableCollection of int and uses a timer to randomly change elements in the collection.

Regs,

Thomas.

Sep 9, 2009 at 3:18 PM

Thomas thanks a lot for the sample. I was incorrectly binding from the XAML.

Sep 10, 2009 at 6:07 PM

Thomas

Thanks for the quick response.

In a similar exercise, the following seems to give a runtime error. It worked well if i have native type in observablecollection.

MainPage.xaml

public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            for (int i = 0; i < 10; ++i)
                _Integers.Add(new Person(_Rnd.Next(100)));

            _Timer.Interval = new TimeSpan(0, 0, 2);
            _Timer.Tick += new EventHandler(_Timer_Tick);
            _Timer.Start();
        }

        void _Timer_Tick(object sender, EventArgs e)
        {
            _Integers[_Rnd.Next(10)].AddIncome(_Rnd.Next(100)); 
        }

        Random _Rnd = new Random();
        System.Windows.Threading.DispatcherTimer _Timer = new System.Windows.Threading.DispatcherTimer();

        ObservableCollection<Person> _Integers = new ObservableCollection<Person>();

        public IValueProvider<int> Sum
        { get { return ExpressionObserver.Execute(_Integers, c => c.Sum(p=>p.Income)).Concrete(); } }
    }

    class Person
    {
        public int Income;
        public Person(int income)
        {
            this.Income = income;
        }
        public void AddIncome (int inc)
        {
            this.Income += inc;
        }
    }
MainPage.xaml
<TextBox Text="{Binding Path=Sum.Value}" />
Coordinator
Sep 10, 2009 at 10:00 PM

Hi Vinay,

Though I have not been able to verify it yet; I think the problem with your code is that the Person class is not public.

Due to CAS restrictions (reflection) when running with Silverlight, Obtics is not allowed to compile expressions with references to members that are not public. Though Income is public it is still hidden because the owning class is not.

If you would like the result to respond to changes in Income you will need to make Income a property, implement INotifyPropertyChanged on Person and raise PropertyChanged events whenever you change the value of income. 

Hope this helps.

Thomas.

Sep 11, 2009 at 8:12 PM

Thomas, that was correct, I had to raise OnPropertyChanged to reflect the changes. That made it work. But if I export an object from a WCF service, and then implement updates, how do I raise the event there. The stub does implement a Notifychanged but how do we further add a OnPropertyChanged for some properties.

Thanks

Vinay

Coordinator
Sep 13, 2009 at 1:42 PM

Hi Vinay,

Unfortunately I'm not much of a WCF expert (yet).

Bottom line is that Obtics needs to be informed when something of interest has changed value. The most common route (for properties) is to implement INotifyPropertyChanged(*). If and how this can be done with (runtime generated?) WCF objects I'm not sure. Most classes generated by tools in VisualStudio are partial classes, so you might be able to insert the logic in a partial class? 

If you have more details about your challenge I might be able to give some hints but no guarantees.

*It is possible to notify Obtics in different ways but these are more complex. If you are interested you can check out the 'CustomMapping and ObticsToXml' projects. I'm sorry that the documentation is still too rudimentary.

Regs,

Thomas.