1

I have have a problem with data binding. I have defined a application resource in XAML like this:

<Application.Resources>
   <local:DataModel x:Key="myDataModel"/>
</Application.Resources>

I bound that model to a list, like this:

<ListView Name="ListBox" 
          ItemsSource="{Binding Source={StaticResource myDataModel}, Path=StatusList}" 
          HorizontalAlignment="Left" 
          HorizontalContentAlignment="Left" 
          VerticalContentAlignment="Top" 
          BorderThickness="0" 
          Background="#000000">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"></StackPanel>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>

    <ListView.ItemTemplate>
        <DataTemplate>
            <Button MinWidth="20" 
                    MinHeight="100" 
                    Background="{Binding Converter={StaticResource StatusConverter}}" 
                    Content="{Binding}" />
        </DataTemplate>
     </ListView.ItemTemplate>
</ListView>

the problem now is that if I change the values of the application resource after binding, the list is not updated. It seems like the binding is done using a copy instead of a reference. The data of the model is updated fine, the PropertyChanged event is raised but the data inside the list never changes.

For your understanding: I have a network client who receives new data every 10 seconds that data needs to be drawn in that list. Right now whenever I receive data, I update the application resource, which as I said should be bound to the list. When I debug the code stopping right in front of the InitializeComponent() method of the XAML file containing the list and wait for a few seconds, I get the latest results of the data transferred, but thats it, it is never updated again.

Can you tell me a better way of defining a globally available instance of my model or a better way of binding it? As you see I need it in more than one part of my program.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
peer
  • 344
  • 1
  • 4
  • 17
  • how do you change the values of the appilcation resource? – punker76 Dec 01 '11 at 12:19
  • Inside my client. The DataModel has a Method called update(Message), where I pass my received message and it updates the values accordingly. So the client knows the DataModel and needs access to it aswell. – peer Dec 01 '11 at 12:25
  • what is your DataModel? a collection? a list? a class? – punker76 Dec 01 '11 at 12:28
  • If it's an ObservableCollection and you are doing list = new List(); this won't work, you need to do a .Clear() and then add elements. – MBen Dec 01 '11 at 12:29
  • The DataModel is a class, it contains a list called StatusList and a few more properties and of cource the method to update the list, its a normal List list, ListStatusList. – peer Dec 01 '11 at 12:30
  • You need to use ObservableCollection as you list to notify when it is changed – MBen Dec 01 '11 at 12:37
  • I have found the problem. MBen, thanks for the hint. I have altered the values inside the list. But what I needed to do was create a new one. All I needed to do was add the line This causes a lot of binding exceptions, I'll try the ObservableCollection this.StatusList = new List() and instead of doing it like this: for(int i=0; i – peer Dec 01 '11 at 12:40

2 Answers2

0
public class DataModel
{
  private IObservableCollection<short> this.statusList;
  public IObservableCollection<short> StatusList
  {
    get {
      return this.statusList;
    }
    set {
      this.statusList = value;
      this.RaisePropertyChanged("StatusList");
    }
  } 
}

now you can do this one

this.StatusList = new ObservableCollection<short>();

hope this helps

EDIT

Here is an example that I am running without any problems.

<Window x:Class="WpfStackOverflowSpielWiese.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfStackOverflowSpielWiese"
        Title="Window1"
        Height="300"
        Width="300">

  <Window.Resources>
    <local:DataModel x:Key="myDataModel" />
    <local:StatusConverter x:Key="StatusConverter" />
  </Window.Resources>

  <Grid>

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

    <Button Grid.Row="0"
            Content="Update"
            Click="Button_Click" />

    <ListView Name="ListBox"
              Grid.Row="1"
              ItemsSource="{Binding Source={StaticResource myDataModel}, Path=StatusList}"
              HorizontalAlignment="Left"
              HorizontalContentAlignment="Left"
              VerticalContentAlignment="Top"
              BorderThickness="0"
              Background="#000000">
      <ListView.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal"></StackPanel>
        </ItemsPanelTemplate>
      </ListView.ItemsPanel>

      <ListView.ItemTemplate>
        <DataTemplate>
          <Button MinWidth="20"
                  MinHeight="100"
                  Background="{Binding Converter={StaticResource StatusConverter}}"
                  Content="{Binding}"></Button>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>

  </Grid>
</Window>


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace WpfStackOverflowSpielWiese
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    public Window1() {
      this.InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e) {
      var dataModel = this.TryFindResource("myDataModel") as DataModel;
      if (dataModel != null) {
        dataModel.UpdateStatusList(new[] {(short)1, (short)2, (short)3});
      }
    }
  }

  public class DataModel : INotifyPropertyChanged
  {
    private ObservableCollection<short> statusList;

    public DataModel() {
      this.StatusList = new ObservableCollection<short>();

      this.UpdateStatusList(new[] {(short)1, (short)2, (short)3});
    }

    public void UpdateStatusList(IEnumerable<short> itemsToUpdate) {
      foreach (var s in itemsToUpdate) {
        this.StatusList.Add(s);
      }
    }

    public ObservableCollection<short> StatusList {
      get { return this.statusList; }
      set {
        this.statusList = value;
        this.RaisePropertyChanged("StatusList");
      }
    }

    private void RaisePropertyChanged(string propertyName) {
      var eh = this.PropertyChanged;
      if (eh != null) {
        eh(this, new PropertyChangedEventArgs(propertyName));
      }
    }

    public event PropertyChangedEventHandler PropertyChanged;
  }

  public class StatusConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
      if (value is short) {
        switch ((short)value) {
          case 1:
            return Brushes.Red;
          case 2:
            return Brushes.Orange;
          case 3:
            return Brushes.Green;
        }
      }
      return Brushes.White;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
      return DependencyProperty.UnsetValue;
    }
  }
}
punker76
  • 14,326
  • 5
  • 58
  • 96
  • Hi punker76, thanks for your response. It did the job of updating the values. But now it throws a lot of Exceptions like this: System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=VerticalContentAlignment; DataItem=null; target element is 'ListViewItem' (Name=''); target property is 'VerticalContentAlignment' (type 'VerticalAlignment') – peer Dec 01 '11 at 12:54
  • I can not imagine that it has something to do with resetting the list. Is the xaml code with the ListView only an excerpt from a whole piece of code? – punker76 Dec 01 '11 at 13:21
  • Yes its the only code in the XAML file, there is also no code inside the code behind file. I think it has to do with the new operator, in when its applied the source gets lost, and the exception is thrown? – peer Dec 01 '11 at 13:46
  • have you tryed to remove HorizontalContentAlignment="Left" VerticalContentAlignment="Top" from ListView – punker76 Dec 01 '11 at 14:00
  • I have tried that but it did not help. Instead it increased the amount of exceptions I got;) – peer Dec 01 '11 at 14:07
  • I didn't try your code, because my version works fine. But you really helped me and showed me the right way, so I want to give you the credit for this! Thank you very much! – peer Dec 01 '11 at 20:29
0

I have solved the problem. I have altered the values inside the list. But what I needed to do was create a new one and add the new values. All I needed to do was add this line:

this.StatusList = new IObservableCollection<short>()

and instead of doing it like this:

for(int i=0; i<ListSize; i++)
    StatusList[i] = i;

i had to do:

for(int i=0; i<ListSize; i++)
    StatusList.add( i );

You also need a little workaround from here: ListBoxItem produces "System.Windows.Data Error: 4" binding error

The surronding element needs to set the alignment properties using styles like this:

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="VerticalContentAlignment" Value="Top" />
</Style>

This way you can avoid the System.Windows.Data Error 4 exceptions

again thanks to everyone who answered! :)

Community
  • 1
  • 1
peer
  • 344
  • 1
  • 4
  • 17