question

Dave010 avatar image
0 Votes"
Dave010 asked Dave010 commented

Is it okay to have "business logic" inside of a BindableLayout's ItemSource?

I have a BindableLayout with a list of objects that contain Command's and methods that dictate what to do when the user completes actions within the specific item. Because this is, technically, no longer a model but a container, with the model and varying functions inside, it almost acts as a ViewModel. But then this means each item inside the BindableLayout is technically a ViewModel. Is it common practice to have the business logic inside of each item?

I've tried to find other ways of getting the method callouts I need outside the container model but there is no other way and I can't find anybody online talking about this practice specifically. Hoping someone here can help. I'm looking for a "No, don't do that because ......" or a "Yes, it is okay to do that because of ...."

The Container Code

 public class ThoughtEntryContainer : INotifyPropertyChanged
     {
         public ICommand SetNTHeightCommand { get; }
         public ICommand SetDTHeightCommand { get; }
         public ICommand SetCTHeightCommand { get; }
         public ICommand OpenDistortionSelectorCommand { get; }
    
         private int thoughtNumber;
         private double ntHeight;
         private double dtHeight;
         private double ctHeight;
         private double maxHeight;
    
         ThoughtEntry thoughtEntryData; // This is the model itself
    
         string distortionLabel;
    
         public ThoughtEntryContainer()
         {
             MaxHeight = -1; // Set to -1 to set Height Request to Auto
    
             SetNTHeightCommand = new Command<StackLayout>(SetNTHeight);
             SetDTHeightCommand = new Command<StackLayout>(SetDTHeight);
             SetCTHeightCommand = new Command<StackLayout>(SetCTHeight);
             OpenDistortionSelectorCommand = new Command<List<Distortion>>(OpenDistortionSelectorPopUp);
    
             SetDistortionLabelText();
         }
    
                 // Extra Code containing commands below here. Removed to save space. Not needed as concept is shown and explained in post
         // ....
     }

dotnet-xamarin
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@Dave010

this means each item inside the BindableLayout is technically a ViewModel

Not clear what confused you. Please elaborate on this.
0 Votes 0 ·

I think I explain it better in a comment to your answer below. But basically, if I put business logic inside of a model (In this case, ICommand's), the model now acts as a ViewModel. I say this because models are usually made to just store data, not perform actions on it. So basically, I'm trying to find out, is it okay to bind a list of viewmodels to a stacklayout.

0 Votes 0 ·

1 Answer

KyleWang-MSFT avatar image
1 Vote"
KyleWang-MSFT answered Dave010 commented

Hi Dave010,

Welcome to our Microsoft Q&A platform!

According to the document: The Model-View-ViewModel Pattern, we can know that "The view model implements properties and commands to which the view can data bind to". So we can declare thoughtEntryData as a property in the ViewModel. We can define the properties, lists or commands (what you called "business logic") which used for data binding in ViewModel.

And here is a simple MVVM demo maybe you can refer to.
Model:

 class TestModel
 {
     public string Description { get; set; }
 }

View:

 <ContentPage.BindingContext>
     <local:TestViewModel/>
 </ContentPage.BindingContext>
        
 <StackLayout BindableLayout.ItemsSource="{Binding .}">
     <Label Text="{Binding testModel.Description}"/>
     <Button Text="click me" Command="{Binding TestCommand}"/>
 </StackLayout>

ViewModel:

 class TestViewModel : INotifyPropertyChanged
 {
     public TestViewModel()
     {
         testModel = new TestModel { Description = "Hello World" };
         TestCommand = new Command(TestMethod);
     }
    
     public ICommand TestCommand { get; }
     public TestModel testModel { get; set; }
    
     void TestMethod()
     {
         Debug.WriteLine("TestCommand");
     }
    
     // ...
 }

Regards,
Kyle


If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

In this example, what if the StackLayout binded to an ObservableCollection of TestModel's. And TestModel had ICommands inside of it. Is that okay for the model of have Commands? I have it working in my personal use-case but I'm not sure if it would cause a memory leak or some other issue that I'm not aware of.

Diving into your example further:
Model:

  class TestModel
  {
      ICommand TestCommand;
      public string Description { get; set; }

      public TestModel()
      {
           TestCommand = new Command(TestMethod);
      }

       void TestMethod()
       {
           Debug.WriteLine("TestCommand");
       }
  }

View:

  <ContentPage.BindingContext>
      <local:TestViewModel/>
  </ContentPage.BindingContext>
            
  <StackLayout BindableLayout.ItemsSource="{Binding TestModelList}">
      <Label Text="{Binding Description}"/>
      <Button Text="click me" Command="{Binding TestCommand}"/>
  </StackLayout>

ViewModel:

  class TestViewModel : INotifyPropertyChanged
  {
      public TestViewModel()
      {
      }
        
      // For sake of example, assume it is properly initalized
      public ObservableCollection<TestModel> TestModelList{ get; set; }
        
      // ...
  }


0 Votes 0 ·

@Dave010 The document also mentioned that "If there's an existing model implementation that encapsulates existing business logic, it can be difficult or risky to change it". So do not add any business logic in Model. Normally, we just declare properties in Model. If you want to do some operations on the model, you can achieve it in ViewModel.

Here is an example.

ViewModel

 public TestViewModel()
 {
     testModel = new TestModel { Description = "Hello World"};
     TestCommand = new Command<TestModel>(testModel =>
     {
         TestMethod(testModel);
     });
 }
    
 public ICommand TestCommand { get; }
 public TestModel testModel { get; set; }
    
 void TestMethod(TestModel testModel)
 {
     Debug.WriteLine(testModel.Description);
 }

XAML

 <Button Text="click me" Command="{Binding TestCommand}" CommandParameter="{Binding testModel}"/>
1 Vote 1 ·

Thank you - that answers my question. I missed that some how. Essentially, it is possible and it can be done but it is not recommended because of the reason you mentioned (If there's an existing model implementation that encapsulates existing business logic, it can be difficult or risky to change it)

0 Votes 0 ·