Click here to Skip to main content
15,886,799 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi All!!

First question here, so go easy on me people! ;-) Also keep in mind, I'm a beginner with VS and VB, using it for a half year now. Forgive me if I use wrong terms, still very new to this.

Situation:
I'm developing a vb.net desktop app in VS2017 using the MVVM pattern. Still learning a lot but making good progress, thx to reading a lot of articles here!

So far I have my UI layer (combination of Windows, User Controls and Interfaces), ViewModes and Data Models. Still have to make the Data Access layer (or implement this within the Data Model, not sure yet).

General problem:
One aspect I have a hard time to "understand" is when to use the private field vs the property of that private field within the class itself. Used the search but didn't find appropriate answers. Is the best approach to use the property members ONLY for the binding or is there no "general rule"?

Example:
Model Class Person has the Default Ctor New() and implements the INotifyPropertyChanged and INotifyDataErrorInfo (through base class). I use the default Ctor because I want designtime data.
Within New() I set the property members (Number and Name) and not the private members (_number and _name). This way the Events are fired. When instantiating a Person class in my VM and using the Bindings in my User Control (and some XAML stuff) I get nice hints with the error messages when showing the window/uc (design choice). Buttons (binding with relay commands) are set and get updated. So far this works perfect and programming it "feels" good.

Specific problem:
But then, when I load a list (function Shared GetList() in Model Class) the events are fired for every new record when using the Default Ctor (and if I set properties within the GetList() they even get fired a second time). So for loading the list I created a second Ctor New() that sets the private members. Because it feels "wrong" that all those events get fired when I don't need them.

Is this okay to do? Use one Ctor for 'initialising' and one Ctor for "loading". Or should I change the way I use Private members and Properties?

Also feel free to post your thought about "my" MVVM implementation. I'm not going for a MVVM purist approach, I'm a single developer and that will stay that way. But are there major disadvantages about the approach I use or is there a better approach? (Or should I make a new question for this?)

(When posting this I didn't see a section to choose, hope it ends up in the right place)

What I have tried:

Create default Ctor and set the Properties
Create a second Ctor and set the Private Fields
Posted
Updated 30-Jan-18 21:57pm
v2

The general idea of having a property to access a private field of a class is to be able to set it outside of that class and hence properties have the "Public" access modifier.
There is no point using the property to access a private variable within the class. Just use the variable. Also, you do not need to call the constructor either. If you're using two-way binding then when you update the property it will automatically be reflected in the view. That is the beauty of the MVVM pattern.
All you need to do is "notify" the view that the property has been updated.
 
Share this answer
 
Comments
Ronald Janssen 31-Jan-18 3:45am    
Hi GKP1992 thx for the reaction. Most of it I understand. But when getting a list of Persons I have to call the constructor for every record don't I?

Example:
Public Shared Function Getlist() As BindingList(Of PersonModel)
Dim result as new BindingList(Of PersonModel)
for x = 1 to 5
Dim person as New PersonModal()
person.number = x (or as you suggest -> person._number = x)
person.name = "Name " & Cstr(x)
result.Add(person)
next
End Function
GKP1992 1-Feb-18 2:21am    
Yes, you'll need to call the constructor for each person as you are creating a new person each time. I misread that, apologies. Yes for PersonModel creating a constructor that sets the private members for each person in GetList. Add them to the result and notify the view about the change in the "list of persons" property to which the list is bound.
Quote:
Model–View–ViewModel (MVVM) is a software architectural pattern.

MVVM facilitates a separation of development of the graphical user interface – be it via a markup language or GUI code – from development of the business logic or back-end logic (the data model). The view model of MVVM is a value converter,[1] meaning the view model is responsible for exposing (converting) the data objects from the model in such a way that objects are easily managed and presented. In this respect, the view model is more model than view, and handles most if not all of the view's display logic.[1] The view model may implement a mediator pattern, organizing access to the back-end logic around the set of use cases supported by the view.
ref: Model–view–viewmodel - Wikipedia[^]

WPF makes this possible via Data Binding[^].

I am an independent software developer and I find the MVVM pattern, along with MEF, a very useful pattern to adhere to.

However, it sounds like you don't want to use the MVVM pattern but want to use the data binding system. That is fine too. Here is an example of using Data Binding without the MVVM Pattern:

XAML Page:
XML
<Window x:Class="WpfSimpleBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        mc:Ignorable="d"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:WpfSimpleBinding"

        Title="Basic code-behin binding example"
        WindowStartupLocation="CenterScreen" Height="400" Width="300">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid.Resources>
            <DataTemplate DataType="{x:Type local:PersonModel}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Name}" Margin="10 3"/>
                    <TextBlock Text="{Binding Age}" Margin="10 3"
                               Grid.Column="1"/>
                </Grid>
            </DataTemplate>
        </Grid.Resources>

        <ListBox ItemsSource="{Binding Persons}">
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
        <Button Content="Randomize" Padding="10 5" Margin="10"
                HorizontalAlignment="Center" VerticalAlignment="Center"
                Grid.Row="1" Click="Button_Click"/>
    </Grid>

</Window>

Base INotifyPropertyChanged implementation (reusable):
C#
public abstract class ObservableBase : INotifyPropertyChanged
{
    public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<TValue>.Default.Equals(field, default(TValue)) || !field.Equals(newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Data Model:
C#
public class PersonModel : ObservableBase
{
    private string name;
    public string Name
    {
        get { return name; }
        set { Set(ref name, value); }
    }

    private int age;
    public int Age
    {
        get { return age; }
        set { Set(ref age, value); }
    }
}

and the Code-Behind for the XAML Page:
C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        Mock();
    }

    public ObservableCollection<PersonModel> Persons { get; set; }
        = new ObservableCollection<PersonModel>();

    private Random rand = new Random();

    private void Mock()
    {
        for (int i = 0; i < 10; i++)
        {
            Persons.Add(new PersonModel
            {
                Name = string.Format("Person {0}", i),
                Age = rand.Next(20, 50)
            });
        }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (var person in Persons)
        {
            person.Age = rand.Next(20, 50);
        }
    }
}

We are using traditional (winform style) control events with WPF Data Binding. The downside of this, that the MVVM pattern resolves, is that the code-behind (ViewModel) is tightly bound to the XAML page and controls.
 
Share this answer
 
Comments
Ronald Janssen 31-Jan-18 4:49am    
Hi Graeme_Grant thx for your reaction. Will study it.

But why do you say "However, it sounds like you don't want to use the MVVM pattern but want to use the data binding system."?

I was under the impression that I'm using the MVVM pattern with databinding. (Maybe not the most purist approach). I have the datacontext of the user controls set to the appropriate ViewModel not to the Model class.

Am I missing something? ;-)
Graeme_Grant 31-Jan-18 5:51am    
The MVVM pattern is decoupling the view and data. It enables testing without the view, switching views without the VM & Model changing, and a lot more.

Data Binding a two-way data change notification system. You can use Data Binding that does not abide to the MVVM pattern. Data Binding does not require a View/Xaml to work.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900