Silverlight MVVM Pattern

Stimulsoft Reports.Silverlight discussion
MtheP
Posts: 24
Joined: Mon Jul 18, 2011 7:37 am

Silverlight MVVM Pattern

Post by MtheP »

Dear Stimulsoft,

Do you have plans to make Report bindable

i.e.

XAML

Code: Select all

<my:StiSLViewerControl HorizontalAlignment="Stretch" Name="ReportTemplateViewer" VerticalAlignment="Stretch" 
                                               Report="{Binding LoadedReport, Converter={StaticResource LoadedReportConverter}}"  />
ViewModel

Code: Select all

public Stream LoadedReport
        {
            get
            {
                return this.loadedReport;
            }

            private set
            {
                this.loadedReport = value;
                this.RaisePropertyChanged("LoadedReport");
            }
        }
ConverterClass

Code: Select all

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var stream = value as Stream;
            if (stream == null)
            {
                return null;
            }

            var report = new StiReport();
            try
            {
                report.Load(stream);
                return report;
            }
            catch (Exception ex)
            {
                throw new ReportLoadException("Report Loading Failed", ex);
            }
        }
HighAley
Posts: 8431
Joined: Wed Jun 08, 2011 7:40 am
Location: Stimulsoft Office

Re: Silverlight MVVM Pattern

Post by HighAley »

Hello.

We don't have plans to implement the Report DependencyProperty of the Viewer.
It could be done easier and faster without binding.

Thank you.
MtheP
Posts: 24
Joined: Mon Jul 18, 2011 7:37 am

Re: Silverlight MVVM Pattern

Post by MtheP »

Dear Stimulsoft,

Thank you for your response but we would like to have this as an option. We are programming to MVVM and placing this in code behind does not work for us. Please consider adding this feature in the future builds. People can still not bind and use code behind if they require.

Kind Regards
HighAley
Posts: 8431
Joined: Wed Jun 08, 2011 7:40 am
Location: Stimulsoft Office

Re: Silverlight MVVM Pattern

Post by HighAley »

Hello.

Please, send a request to support@stimulsoft.com with a link on this topic.

Thank you.
MtheP
Posts: 24
Joined: Mon Jul 18, 2011 7:37 am

Re: Silverlight MVVM Pattern

Post by MtheP »

Dear All,

For all the people who want to use MVVM pattern below is the code to create a new property. Works a treat and no code behind. If anyone is interested I have also wrote a control for setting StiReportOptions including events in MVVM

In the XAML

Code: Select all

<my:StiSLViewerControl HorizontalAlignment="Stretch" Name="ReportTemplateViewer" 
                         VerticalAlignment="Stretch" Property:StiViewModelAdapter.ReportStream="{Binding ReportStream}"
                                               Property:StiViewModelAdapter.ReportBusinessObjects="{Binding BusinessObjects}"/>

Code: Select all


public class ReportBusinessObjects : ObservableObject
    {
        #region Fields

        /// <summary>
        ///   The value
        /// </summary>
        private object value;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets the category.
        /// </summary>
        public string Category { get; set; }

        /// <summary>
        ///   Gets or sets the name.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        ///   Gets or sets the sub business ojects.
        /// </summary>
        /// <value> The sub business ojects. </value>
        public IEnumerable<string> SubBusinessOjects { get; set; }

        /// <summary>
        ///   Gets or sets the value.
        /// </summary>
        public object Value
        {
            get
            {
                return this.value;
            }

            set
            {
                this.value = value;
                this.RaisePropertyChanged("Value");
            }
        }

        #endregion

public sealed class StiViewModelAdapter
    {
        #region Static Fields

        /// <summary>
        /// The report business objects property.
        /// </summary>
        public static readonly DependencyProperty ReportBusinessObjectsProperty =
            DependencyProperty.RegisterAttached(
                "ReportBusinessObjects", 
                typeof(List<ReportBusinessObjects>), 
                typeof(StiViewModelAdapter), 
                new PropertyMetadata(OnReportBusinessObjectsChanged));

        /// <summary>
        /// The report stream property.
        /// </summary>
        public static readonly DependencyProperty ReportStreamProperty =
            DependencyProperty.RegisterAttached(
                "ReportStream", typeof(Stream), typeof(StiViewModelAdapter), new PropertyMetadata(OnReportStreamChanged));

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The get report business objects.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The List of Business Reports/>.</returns>
        /// <remarks>No Remarks</remarks>
        public static List<ReportBusinessObjects> GetReportBusinessObjects(UIElement element)
        {
            return (List<ReportBusinessObjects>)element.GetValue(ReportBusinessObjectsProperty);
        }

        /// <summary>
        /// The get report stream.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The <see cref="Stream" />.</returns>
        /// <remarks>No Remarks</remarks>
        public static Stream GetReportStream(UIElement element)
        {
            return (Stream)element.GetValue(ReportStreamProperty);
        }

        /// <summary>
        /// The set report business objects.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        /// <remarks>No Remarks</remarks>
        public static void SetReportBusinessObjects(UIElement element, List<ReportBusinessObjects> value)
        {
            element.SetValue(ReportBusinessObjectsProperty, value);
        }

        /// <summary>
        /// The set report stream.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        /// <remarks>No Remarks</remarks>
        public static void SetReportStream(UIElement element, Stream value)
        {
            element.SetValue(ReportStreamProperty, value);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The on report business objects changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        /// <remarks>No Remarks</remarks>
        private static void OnReportBusinessObjectsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var viewer = sender as StiSLViewerControl;
            var designer = sender as StiSLDesignerControl;
            var businessObjects = GetReportBusinessObjects(viewer == null ? designer : (UIElement) viewer);
            if (viewer == null && designer == null)
            {
                return;
            }

            var report = viewer == null ? designer.Report : viewer.Report;
            if (report == null)
            {
                return;
            }

            report.CalculationMode = StiCalculationMode.Interpretation;
            report.BusinessObjectsStore.Clear();
            foreach (var reportBusinessObject in businessObjects)
            {
                report.RegBusinessObject(reportBusinessObject.Category, reportBusinessObject.Name, reportBusinessObject.Value);
                report.Dictionary.Synchronize();
                var businessObject = report.Dictionary.BusinessObjects[reportBusinessObject.Name];

                if (reportBusinessObject.SubBusinessOjects == null)
                {
                    continue;
                }

                businessObject.BusinessObjects.Clear();
                foreach (var subBusObjectName in reportBusinessObject.SubBusinessOjects)
                {
                    businessObject.BusinessObjects.Add(new StiBusinessObject { Name = subBusObjectName });
                    report.Dictionary.SynchronizeBusinessObjects();
                }                
            }
            
            report.Dictionary.SynchronizeBusinessObjects();
            report.Render();
        }

        /// <summary>
        /// The on report stream changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        /// <remarks>No Remarks</remarks>
        private static void OnReportStreamChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var viewer = sender as StiSLViewerControl;
            var designer = sender as StiSLDesignerControl;
            var businessObjects = GetReportBusinessObjects(viewer == null ? designer : (UIElement)viewer);
            var stream = e.NewValue as Stream;
            if ((viewer == null && designer == null) || stream == null)
            {
                return;
            }

            var report = new StiReport();
            report.Load(stream);
            report.BusinessObjectsStore.Clear();
            foreach (var reportBusinessObject in businessObjects)
            {
                report.RegBusinessObject(reportBusinessObject.Category, reportBusinessObject.Name, reportBusinessObject.Value);
                var businessObject = report.Dictionary.BusinessObjects[reportBusinessObject.Name];
                if (reportBusinessObject.SubBusinessOjects == null)
                {
                    continue;
                }

                businessObject.BusinessObjects.Clear();
                foreach (var subBusObjectName in reportBusinessObject.SubBusinessOjects)
                {
                    businessObject.BusinessObjects.Add(new StiBusinessObject { Name = subBusObjectName });
                }
            }

            if (viewer != null)
            {
                viewer.Report = report;
            }

            if (designer != null)
            {
                designer.Report = report;
            }


            report.Render();
        }

        #endregion
    }
HighAley
Posts: 8431
Joined: Wed Jun 08, 2011 7:40 am
Location: Stimulsoft Office

Re: Silverlight MVVM Pattern

Post by HighAley »

Hello.

Thank you for posting your solution.
victorperez2911
Posts: 3
Joined: Tue Feb 10, 2015 11:38 am

Re: Silverlight MVVM Pattern

Post by victorperez2911 »

Stimulsoft really do not intend to adjust its components in Silverlight for compatibility with MVVM?

I say this because I tried to use the code posted by mthep, and apparently missing some piece of code, to be precise is absent the logic to capture any event that will occur whenever the Designer Control change Report property, so that it can update the value of the DependencyProperty.

Could you help me?

Victor Perez
Alex K.
Posts: 6488
Joined: Thu Jul 29, 2010 2:37 am

Re: Silverlight MVVM Pattern

Post by Alex K. »

Hello,

Unfortunately, we don't have plans to implement the Report DependencyProperty.

Thank you.
Eugene
Posts: 28
Joined: Sat Aug 12, 2006 9:11 am
Location: Ekaterinburg, Russia

Re: Silverlight MVVM Pattern

Post by Eugene »

Since I'm trying to adapt MtheP's approach to a MVVM application, I'll post a reply in this thread. The code works fine and bindings work fine, I can render and view the report with data with the posted code.

In this approach I get StiBusinessObjects for all the datasources, that I feed to the report object. Let's say, there is a "Product" StiBusinessObject, containing the records for several products. If I create a simple databand, all is good.

Now I go further. I need to do some calculations, based on the items of the collection. Namely, get a string, containing a comma-delimited list of all products. For this I go to code. What I've been doing with the "data from datatables" is I had a loop to iterate the objects and had indexing available. Here I need to make a different loop:

Code: Select all

 
public string Do()
  {
   string x = "";
   
   Product.First();
   do
   {
    x+=Product.RegNo + ", ";
    Product.Next();
   } while (!Product.IsEof);
   
   return x;
  }
And it works too.

Now the question. Is there a way to cast the Product StiBusinessObject to IEnumerable, so that I can have something like:

Code: Select all

 
public string Do()
  {
   string x = "";
   
  foreach (var y in ProducAsIEnumerable)
  {
     x+=y.RegNo + ", ";
  }

  return x;
  }
I'm trying to avoid the First-Next-Eof logic here and be able to address to a specific Product from the collection throughout the code.
HighAley
Posts: 8431
Joined: Wed Jun 08, 2011 7:40 am
Location: Stimulsoft Office

Re: Silverlight MVVM Pattern

Post by HighAley »

Hello.

If you need to cast your BusinessObjects, it should inherit IEnumerable.
You could get access to the BusinessObject using Current property.

Code: Select all

ProducAsIEnumerable.Current
Thank you
Locked