Hansi
Topic Author
Posts: 12
Joined: 24 May 2017, 11:30

Data-Binding: Right way to update ObservableCollection

06 Sep 2017, 17:04

I'm playing around with the data-binding examples.
https://www.noesisengine.com/docs/Gui.C ... orial.html

I successfully tested the "Binding to a Collection" example.

But what's not covered there, is how I can update this particular ObservableCollection to automatically synchronize and add a player in the ListBox.
The tutorial says, ObservableCollection updates itself, but I can't confirm that... Once the ListBox is initially filled, I am unable to modify it any further.

What do I have to do to add an additional Player entry into the ListBox in the tutorial to a later point?
 
User avatar
sfernandez
Site Admin
Posts: 2323
Joined: 22 Dec 2011, 19:20

Re: Data-Binding: Right way to update ObservableCollection

06 Sep 2017, 23:51

I suppose you are setting the ObservableCollection in the ListBox.ItemsSource property. And you defined an appropriate DataTemplate in the ListBox.ItemTemplate property (or used DisplayMemberPath property instead). Once you do that, adding/removing to/from the collection should update the ListBox automatically, there is no need to do anything manually.
<ListBox ItemsSource="{Binding Players}" DisplayMemberPath="Name"/>
public class Player
{
  public string Name { get; set; }
}

public class ViewModel
{
  public ObservableCollection<Player> Players { get; private set; }
  public ViewModel() { Players = new ObservableCollection<Player>(); }
}

...

void OnAddPlayer(string name)
{
  ViewModel vm = ...;
  vm.Players.Add(new Player { Name = name });
}
void OnRemovePlayer(Player player)
{
  ViewModel vm = ...;
  vm.Players.Remove(player);
}
 
Hansi
Topic Author
Posts: 12
Joined: 24 May 2017, 11:30

Re: Data-Binding: Right way to update ObservableCollection

07 Sep 2017, 08:37

But to access the Players property of the ViewModel class, I can only instantiate a new object and can't access the "original" Players collection (?).
I guess I'm having a huge understanding problem here:

To not leave anything out, this is the xml (unchanged from the tutorial):
<Grid
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="600">

    <Grid.Resources>
        <DataModel3 x:Name="dataModel" />

        <DataTemplate x:Key="TaskTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="100"/>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition Width="200"/>
                </Grid.ColumnDefinitions>

                <Rectangle Width="15" Height="10" Fill="{Binding Color}" Stroke="Transparent" StrokeThickness="0"
                    Margin="5, 0, 5, 0" Grid.Column="0"/>
                <TextBlock Text="{Binding Name}" Margin="5, 0, 5, 0" Grid.Column="1"/>
                <TextBlock Text="{Binding Scale, StringFormat=P0}" Margin="5, 0, 5, 0" Grid.Column="2"/>
                <TextBlock Text="{Binding Pos}" Margin="5, 0, 5, 0" Grid.Column="3"/>
            </Grid>
        </DataTemplate>
    </Grid.Resources>

    <ListBox Height="100" DataContext="{StaticResource dataModel}"
        ItemsSource="{Binding Players}"
        ItemTemplate="{StaticResource TaskTemplate}" />

</Grid>
The classes are also unchanged:
public class Player
{
    public Player(string name, Noesis.Color color, float scale, string pos)
    {
        Name = name;
        Color = new SolidColorBrush(color);
        Scale = scale;
        Pos = pos;
    }

    public string Name { get; private set; }
    public Brush Color { get; private set; }
    public float Scale { get; private set; }
    public string Pos { get; private set; }

}

public class DataModel3
{
    public DataModel3()
    {
        Players = new ObservableCollection<Player>();
        Players.Add(new Player("Player0", Colors.Red, 1.0f, "(0,0,0)"));
        Players.Add(new Player("Player1", Colors.Gray, 0.75f, "(0,30,0)"));
        Players.Add(new Player("Player2", Colors.Orange, 0.50f, "(0,-10,0)"));
        Players.Add(new Player("Player3", Colors.Green, 0.85f, "(0,-10,0)"));
    }

    public ObservableCollection<Player> Players { get; private set; }
}
Now what can I do in my code to update the List?
In your example you left out the (for me) important part:
ViewModel vm = ...;
vm.Players.Add(new Player { Name = name });
What do I have to write for "..."?

I tried this:
    public void AddPlayer()
    {
        Debug.Log("AddPlayer button clicked");
        DataModel3 dm = new DataModel3();
        dm.Players.Add(new Player("Player4", Colors.Yellow, 3.0f, "(5,0,0)"));
    }
    
Nothing happens...
 
User avatar
ai_enabled
Posts: 223
Joined: 18 Jul 2013, 05:28
Contact:

Re: Data-Binding: Right way to update ObservableCollection

07 Sep 2017, 09:25

Hansi, sorry for maybe being rude, but are you a novice programmer? You need a basic knowledge of OOP if you want to develop something with NoesisGUI. The tutorials are actually very straightforward if you know OOP and have some programming experience. Just keep this in mind.

Let's see what's the issue here:
 public void AddPlayer()
    {
        Debug.Log("AddPlayer button clicked");
        DataModel3 dm = new DataModel3();
        dm.Players.Add(new Player("Player4", Colors.Yellow, 3.0f, "(5,0,0)"));
    }
You create a new instance of DataModel3 class and and a new player to its Players collection... It will not work as your XAML view is bound to another DataModel3 instance.
Find the code where you create the new DataModel3 for the first time and save this created instance in a field. Then you need to use this field to add the new player to the collection. Do not create new DataModel3, use the existing one from the field. I hope it helps.
AtomicTorch Studio Pte. Ltd. http://atomictorch.com
 
Hansi
Topic Author
Posts: 12
Joined: 24 May 2017, 11:30

Re: Data-Binding: Right way to update ObservableCollection

07 Sep 2017, 09:59

No worries, yes I am a novice programmer :)
But thank you for helping me out, anyway.
That's what I thought, but desperation made me try these things.

That's because my question is (like I said in my last post): How can I find the "original" object, because there is none created in the tutorial.
It's just the initial constructor of DataModel3 which creates the Players Collection.

Again, there has no object been created explicitly by me. So how do I access this collection, when there is no existing object?
 
User avatar
ai_enabled
Posts: 223
Joined: 18 Jul 2013, 05:28
Contact:

Re: Data-Binding: Right way to update ObservableCollection

07 Sep 2017, 10:15

Hansi, I checked the tutorial code for this example and I can agree it's not really straightforward here, even for non-novice programmers :-) . You can't access this data object easily as it's defined as a static resource. It was done on purpose to demonstrate how the data binding for collections works, but it's a bad example as it's hard to do the collection modification.

The common approach is to create a view model class instance (in that case, DataModel3) in the codebehind of the UserControl, then assign it to some field and this.DataContext property.
Then in XAML you can bind to properties of this view model instance. When you need to modify something in your view model instance, you can access it through the field.
Alas, I can't find any good tutorial for it there https://www.noesisengine.com/docs/Gui.Core.Index.html (Unity UserControl sample here is so complicated!) or on Github... so perhaps NoesisGUI team will create a new, really straightforward sample to demonstrate this approach.
AtomicTorch Studio Pte. Ltd. http://atomictorch.com
 
Hansi
Topic Author
Posts: 12
Joined: 24 May 2017, 11:30

Re: Data-Binding: Right way to update ObservableCollection

07 Sep 2017, 10:40

Thank you very much for your dedication, ai_enabled!

ListBox.DataContext did the trick!

I wanted to try that approach some time ago, but I was so stuck on the tutorial template code that i never went the obvious way...

An updated tutorial doesn't sound like a bad idea, I agree. It doesn't prepare for the full data-binding potential :)
 
User avatar
sfernandez
Site Admin
Posts: 2323
Joined: 22 Dec 2011, 19:20

Re: Data-Binding: Right way to update ObservableCollection

14 Sep 2017, 00:39

Trying to put in code what aienabled was talking about, in case is useful for others:

Having a xaml like this:
<UserControl x:Class="PlayersList"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    ...
    <ListBox ItemsSource="{Binding Players}" DisplayMemberPath="Name"/>
    ...
</UserControl>
The code-behind (and related classes) would look something like this:
public class Player
{
  public string Name { get; set; }
  ...
}

public class PlayersListVM
{
  public PlayersListVM() { Players = new ObservableCollection<Player>(); }
  public ObservableCollection<Player> Players { get; private set; }
  ...
}

public class PlayersList : Noesis.UserControl
{
  private PlayersListVM playersListVM;
  
  public PlayersList()
  {
    InitializeComponent();
    
    playersListVM = new PlayersListVM();
    DataContext = playersListVM;
  }
  
  private void InitializeComponent()
  {
    Noesis.GUI.LoadComponent(this, "...path_to_PlayersList.xaml....");
  }
  
  void OnAddPlayer(string name)
  {
    playersListVM.Players.Add(new Player { Name = name });
  }
  
  void OnRemovePlayer(Player player)
  {
    playersListVM.Players.Remove(player);
  }
  
  ...
}
Hope this helps.
 
User avatar
jsantos
Site Admin
Posts: 3201
Joined: 20 Jan 2012, 17:18
Contact:

Re: Data-Binding: Right way to update ObservableCollection

18 Sep 2017, 18:24

Now that we are working in the new application framework, all examples are being improved. Thanks for this feedback!

Who is online

Users browsing this forum: No registered users and 1 guest