0

I would like to bind ObservableCollection with Listbox in WPF application. So when elements in the ObservableCollection will be modified the ListBox will update itself.

There is a public static ObservableCollection<Camera> extension = new ObservableCollection<Camera>(); in class Camera

And the ListBox is in the class MainWindow.xaml

I tried that, but it does not work:

enter image description here

Camera class:

       using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace HomeSecurity {

    public class Camera : INotifyPropertyChanged {
        public static readonly Regex AxisMacPattern = new Regex("00408[Cc][a-zA-Z0-9]{6}");
        public string _IP;
        public string IP {
            get {
                return _IP;
            }
            set {

                if (_IP != value) {
                    _IP = value;
                    OnPropertyChanged("IP");
                }

            }
        }
        public string _HTTPPort;
        public string HTTPPort {
            get {
                return _HTTPPort;
            }
            set {

                if (_HTTPPort != value) {
                    _HTTPPort = value;
                    OnPropertyChanged("HTTP");
                }

            }
        }
        public string _MAC;
        public string MAC {
            get {
                return _MAC;
            }
            set {

                if (_MAC != value) {
                    _MAC = value;
                    OnPropertyChanged("MAC");
                }

            }
        }
        public string _ServiceName;
        public string ServiceName {
            get {
                return _ServiceName;
            }
            set {

                if (_ServiceName != value) {
                    _ServiceName = value;
                    OnPropertyChanged("ServiceName");
                }

            }
        }
        public string _FullName;
        public string FullName {
            get {
                return _FullName;
            }
            set {

                if (_FullName != value) {
                    _FullName = value;
                    OnPropertyChanged("FullName");
                }

            }
        }
        public string _HostName;
        public string HostName {
            get {
                return _HostName;
            }
            set {

                if (_HostName != value) {
                    _HostName = value;
                    OnPropertyChanged("HostName");
                }

            }
        } 

        public Camera() { }
        public Camera(string MAC) : this(null, null, MAC, null, null, null) { }
        public Camera(string MAC, string ServiceName) : this(null, null, MAC, ServiceName, null, null) { }
        public Camera(string IP, string HTTPPort, string MAC, string ServiceName, string FullName, string HostName) {
            this.IP = IP;
            this.HTTPPort = HTTPPort;
            this.MAC = MAC;
            this.ServiceName = ServiceName;
            this.FullName = FullName;
            this.HostName = HostName;
            AddToExtension(this);
        }
        public static ObservableCollection<Camera> _extension = new ObservableCollection<Camera>();
        //

        public ObservableCollection<Camera> extension {
            get { return _extension; }
            set {
                if (_extension != value) {
                    _extension = value;
                    OnPropertyChanged("extension");
                }

            }
        }
        private void OnPropertyChanged(string propertyName) {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion


        // 

        public static void AddToExtension(Camera camera) {
            _extension.Add(camera);
        }

        public static void RemoveFromExtension(Camera camera) {
            _extension.Remove(camera);
        }

        public static Camera GetFromExtension(String MAC) {
            foreach (Camera camera in _extension)
                if (camera.MAC.Equals(MAC))
                    return camera;
            return null;
        }

        public static void PrintExtension() {
            foreach (Camera camera in _extension)
                Console.WriteLine(camera);
        }

        public override string ToString() {
            return "IP: " + IP + " HTTP Port: " + HTTPPort + " MAC: " + MAC + " Service Name: " + ServiceName + " FullName: " + FullName + " HostName: " + HostName;
        }
    }
}

XAML:

  <Window x:Class="HomeSecurity.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:HomeSecurity" 
        Title="MainWindow" WindowState="Maximized" Loaded="Window_Loaded"

        >

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*" />
            <RowDefinition Height="8*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="1366" />
        </Grid.ColumnDefinitions>
        <Border BorderBrush="Red" BorderThickness="4" Grid.Column="1" Grid.Row="0">
            <ListBox x:Name="CameraListBox"
         ItemsSource="{Binding Path=Camera.extension}">
                <ListBox.Resources>
                    <DataTemplate DataType="{x:Type local:Camera}">
                        <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                           <TextBox Text="Hello World" /> 
                        </Border>
                    </DataTemplate>
                </ListBox.Resources>
            </ListBox>
        </Border>

        <Border BorderBrush="Green" BorderThickness="2" Grid.Column="1" Grid.Row="1">
            <ScrollViewer >
                <WrapPanel x:Name="VideoPanel" >
                </WrapPanel>
            </ScrollViewer>
        </Border>


    </Grid>

</Window>

MainWindow.xaml.cs:

using Bonjour;

namespace HomeSecurity {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged {

        public MainWindow() {
            DataContext = this;
            InitializeComponent();

        //   this.DataContext = this;
        }
       //
        private Camera _camera;
        public Camera Camera
        {
            get { return _camera; }
            set
            {
                if (_camera != value)
                {
                     _camera= value;
                     OnPropertyChanged("Camera");
                }

            }
        }

        /// <summary>
        /// Raises the PropertyChanged notification in a thread safe manner
        /// </summary>
        /// <param name="propertyName"></param>
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
        //
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            createGUI();
        }

        private void createGUI() {
            Console.WriteLine("dupa");
            Scanner.ScanService();
      //      startListening();
            //THIS CODE WON'T RUN BECAUSE   Scanner.ScanService(); have frozen it
            AddVideoStream("192.168.0.2");
            AddVideoStream("192.168.0.2");
            AddVideoStream("192.168.0.2");
        }

        private void startListening() {
            Camera._extension.CollectionChanged += (s, e) => {
             //  CameraListBox.Items.Add(Camera.extension.Last());
            };
        }


        //TEN
        private void AddVideoStream(String sourceIP) {
            int cols = 2;
            int formsHostWidth = (int)(VideoPanel.ActualWidth / cols) - 4;

            WindowsFormsHost formsHost = new WindowsFormsHost();
            VideoStream videoStream = new VideoStream(sourceIP);
            formsHost.Width = formsHostWidth;
            formsHost.Height = videoStream.GetPrefferedHeight(formsHostWidth);
            formsHost.Child = videoStream;
            Border lineBorder = new Border();
            lineBorder.BorderBrush = Brushes.Green;
            lineBorder.BorderThickness = new Thickness(2);
            lineBorder.Child = formsHost;
            VideoPanel.Children.Add(lineBorder);

        }
    }
}

enter image description here

If I change constructor in MAinWindow.xaml.cs to:

  InitializeComponent();
            Camera = new Camera();
            DataContext = this;

I get:

enter image description here

but this is not updated data... it is data frome the time where the Camera object was inserted in the extension.

16
  • 1
    You could try adding a dummy object and removing it right away. But I'm not sure exactly what you are trying to accomplish? Have you considered having your UI bounded to the INotifyPropertyChange of the individual objects in your collection instead? Commented Jan 15, 2014 at 3:51
  • 1
    Just set it to the ListBox's ItemSource to your ObservableCollection, it will listen when items are added/removed. Commented Jan 15, 2014 at 3:59
  • 1
    What about <ListBox x:Name="CameraListBox" ItemsSource="{Binding Path=Camera.extension}">? Assuming your DataContex is correct. I think that's the right syntax, not at my work PC though. Commented Jan 15, 2014 at 4:11
  • 1
    Does Camera implement INotifyPropertyChanged (and the extension property)? If not you are binding to a null value, and your UI never is updated when the observable collection is created and assigned to extension. Commented Jan 15, 2014 at 4:21
  • 1
    You will need to implement that (or set it before InitalizeComponent())- see my answer on this post - stackoverflow.com/questions/20664707/… Commented Jan 15, 2014 at 4:38

2 Answers 2

2

You don't want to use a static property unless you really want to be shared between all instances of your class.

When your UI is initialized extension will be null. So the binding will be setup to null and nothing will happen. What you need to do is let your UI know when extention is updated, so it can listen for when new objects are added. Does that make sense?

Your example above, the property is not calling PropertyChangedEventArgs when extension is created so it is not actually listening to your collection.

public class Camera : INotifyPropertyChanged
{
        private ObservableCollection<Camera> _extension;
        public ObservableCollection<Camera> extension;
        {
            get { return _extension; }
            set
            {
                if (_extension != value)
                {
                     _extension= value;
                     OnPropertyChanged("extension");
                }

            }
        }

        /// <summary>
        /// Raises the PropertyChanged notification in a thread safe manner
        /// </summary>
        /// <param name="propertyName"></param>
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

}

Also add this to your constructor DataContext = this, and implement INotifyPropertyChanged in your window class also. Something like this

public partial class MainWindow : Window, INotifyPropertyChanged
{
        public MainWindow() {
            DataContext = this;
            InitializeComponent();
        }

        // ... 

        private Camera _camera;
        public Camera Camera;
        {
            get { return _camera; }
            set
            {
                if (_camera != value)
                {
                     _camera= value;
                     OnPropertyChanged("Camera");
                }

            }
        }

        /// <summary>
        /// Raises the PropertyChanged notification in a thread safe manner
        /// </summary>
        /// <param name="propertyName"></param>
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
}

I think you need to have a data template for something to show up too

<ListBox x:Name="CameraListBox"
         ItemsSource="{Binding Path=Camera.extension}">
    <ListBox.Resources>
        <DataTemplate DataType="{x:Type local:Camera}">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                <TextBox Text="Hello World" />
            </Border>
        </DataTemplate>
    </ListBox.Resources>
</ListBox>
Sign up to request clarification or add additional context in comments.

18 Comments

You can make it static if you want, you just need to make OnPropertyChanged static too.
You'll need to implement INotifyPropertyChange on the MainWindow also, so it knows when Camera is set.
Your UI should be listening to each item and responding to them (via INotifyPropetyChange on Camera). I don't understand why the ListBox needs to be updated directly. Maybe I'm just not understanding the problem?
@Yoda thats because you don't call OnPropertyChanged method in setter of IP, HTTPPort, MAC, and other properties in Camera class
See my updated answer, I added MainWindow and INotify - you implement it just like we did for camera. And @har07 is right, it needs to be updated for ALL properties that you are using in the UI (even if it's part of an object chain). Otherwise DataBinding won't work properly if any are missing. Basically add OnPropertyChanged("<PROPERTY NAME"); any time any property changes.
|
2

Try to create a property that return extension static field, then bind your ListBox to that property. As far as I know you have to bind to property instead of field.

public static ObservableCollection<Camera> extension = new ObservableCollection<Camera>();
public ObservableCollection<Camera> bindableExtension 
{ 
    get { return extension; }
}

UPDATE :

As I can see from update you set DataContext to code behind. This means, you have to create a property named Camera in MainWindow.xaml.cs. Then you have to either implement INotifyPropertyChanged there or initialize Camera property before setting the DataContex :

public MainWindow() {
            InitializeComponent();
            this.Camera = new Camera();
            this.DataContext = this;
        }
...
public Camera Camera { get; set; }

4 Comments

I copied your code and then added: <ListBox x:Name="CameraListBox" ItemsSource="{Binding Path=Camera.bindableExtension}" /> in XAML. But no effect. Do I have to do something about DataContext or this INotifyPropertyChanged ?
of course you have to set DataContext somewhere (in XAML or c#), and I can't see you did it in the XAML/codes posted in question.
In the op is current code. I added that what you posted but the problem is that it works as bad as when I did it by this code: Camera._extension.CollectionChanged += (s, e) => { CameraListBox.Items.Add(Camera.extension.Last()); }; When the object in the Camera.extension is updated -> field has changed nothing happens.
I did all you and ansible said. Could you please look at the op. Currently nothing goes into listBox.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.