0

So I have the following XAML:

<TextBlock Text="{Binding DisconnectedDevices, UpdateSourceTrigger=PropertyChanged}" />

The view model has the following properties:

public string DisconnectedDevices {get; set;}
public IEnumerable<IDeviceInformationVM> DeviceCollection {get; set;}

There's a method that gets called which raises the property notified event:

public void DeviceCollectionChanged()
{
    RaisePropertyChanged(() => DeviceCollection);
}

I'd like to update the value in the TextBlock when DeviceCollection changes. I'm aware that I could just call RaisePropertyChanged on DisconnectedDevices but I'm wondering if its possible to update a TextBlock on a different property change event.

Thanks all!

EDIT: Thanks for the suggestions for using an ObservableCollection instead of IEnumerable, unfortunately, I'm not at liberty to change the collection type..

The DeviceCollectionChanged method is called whenever the collection changes (tedious I know...)

FURTHER EDIT: Have just gone ahead with

RaisePropertyChanged(() => DisconnectedDevices);

I appreciate not enough information might have been provided in the question to get what I was trying to do, apologies for that

redspidermkv
  • 503
  • 10
  • 25
  • 1
    The question doesn't make sense. Call RaisePropertyChanged on the DisconnectedDevices property, that's what INotifyPropertyChanged was invented for. Besides that, remove `UpdateSourceTrigger=PropertyChanged` from the binding. It is redundant, as a TextBlock never actively changes its Text property. – Clemens Feb 24 '16 at 10:11
  • @Clemens it's not always the truth about default value for UpdateSourceTrigger. For Text it could be LostFocus https://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger(v=vs.110).aspx – chameleon Feb 24 '16 at 10:15
  • @chameleon86 Which would only be applicable if we would talk about a two-way binding, i.e. a control that can change its Text property (e.g. by user input like a TextBox). Here we have a TextBlock, which never changes its Text property, i.e. a one-way binding. The source property of this binding is never set by the binding, hence UpdateSourceTrigger is entirely redundant. – Clemens Feb 24 '16 at 10:29

3 Answers3

0

I am not sure if your current code works, but assuming it works. Why not use - ObservableCollection<IDeviceInformationVM> instead of IEnumerable<IDeviceInformationVM> DeviceCollection you wont need the DeviceCollectionChanged event. It will be taken care.

Yes you can raise

public void DeviceCollectionChanged()
{
    RaisePropertyChanged(() => DeviceCollection);
    RaisePropertyChanged(() => DisconnectedDevices);
   // or RaisePropertyChanged("DisconnectedDevices"); Whichever works
}

See this question, it might help you with implementation of NotifyPropertyChanged for multiple properties- WPF Notify PropertyChanged for a Get Property

Community
  • 1
  • 1
Carbine
  • 7,849
  • 4
  • 30
  • 54
0

Do you call the DeviceCollectionChanged() method everytime you change your DeviceCollection? How do you set DeviceCollection?

You can implement an ObservableCollection (bottom of this answer), or, depending on how you set your DeviceCollection, if for example DeviceCollection comes from a list, you can implement something like this:

private IEnumerable<IDeviceInformationVM> deviceCollection;
public IEnumerable<IDeviceInformationVM> DeviceCollection 
{
 get
  {
    return deviceCollection;
  }
  set
  {
    deviceCollection = value; 
    RaisePropertyChanged(() => DisconnectedDevices);
    RaisePropertyChanged(() => DeviceCollection);
  }
}

DeviceCollection = GetListOfIDeviceInformationVM(); //will automatically raise property changed and update your TextBlock

You won't have to keep on calling RaisePropertyChanged() which looks rather tedious

Community
  • 1
  • 1
Tyress
  • 3,573
  • 2
  • 22
  • 45
0

Change the type of the CollectionDevice collection to ObservableCollection then, raise the event CollectionChanged as follows : DeviceCollection.CollectionChanged + = DeviceCollection_CollectionChanged; I give you an implemention in MVVM with a class RelayCommand

here the view : (MainView)

<Window x:Class="WpfApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

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

    <TextBlock Text="{Binding DisconnectedDevices, Mode=TwoWay}" Height="25" Width="175" Grid.Row="0" />
    <Button Grid.Row="1" Content="Click" Command="{Binding ToggleExecuteCommand}"  Width="100" Height="25"/>

</Grid>

the ViewModel (Main ViewModel)

    using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;

namespace WpfApplication
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private string disconnectedDevices;

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        public MainViewModel()
        {
            ToggleExecuteCommand = new RelayCommand(ChangeCollection);
            DeviceCollection = new ObservableCollection<DeviceInformationVM>();
            DeviceCollection.CollectionChanged += DeviceCollection_CollectionChanged;
        }

        private void ChangeCollection(object obj)
        {
            DeviceCollection.Add(new DeviceInformationVM { MyProperty = "TEST" });
        }

        private void DeviceCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            NotifyCollectionChangedAction action = e.Action;

            if (action == NotifyCollectionChangedAction.Add)
            {
                DisconnectedDevices = "Somme thing added to collection";
            }

            if (action == NotifyCollectionChangedAction.Remove)
            {
                DisconnectedDevices = "Somme thing removed from collection";
            }
        }

        public string DisconnectedDevices
        {
            get { return this.disconnectedDevices; }

            set
            {
                if (value != this.disconnectedDevices)
                {
                    this.disconnectedDevices = value;
                    NotifyPropertyChanged("DisconnectedDevices");
                }
            }
        }

        public ObservableCollection<DeviceInformationVM> DeviceCollection { get; set; }

        public RelayCommand ToggleExecuteCommand { get; set; }

    }
}

the RelayCommand :

using System;

using System.Windows.Input;

namespace WpfApplication { public class RelayCommand : ICommand { private Action execute;

    private Predicate<object> canExecute;

    private event EventHandler CanExecuteChangedInternal;

    public RelayCommand(Action<object> execute)
        : this(execute, DefaultCanExecute)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        if (canExecute == null)
        {
            throw new ArgumentNullException("canExecute");
        }

        this.execute = execute;
        this.canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
            this.CanExecuteChangedInternal += value;
        }

        remove
        {
            CommandManager.RequerySuggested -= value;
            this.CanExecuteChangedInternal -= value;
        }
    }

    public bool CanExecute(object parameter)
    {
        return this.canExecute != null && this.canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        this.execute(parameter);
    }

    public void OnCanExecuteChanged()
    {
        EventHandler handler = this.CanExecuteChangedInternal;
        if (handler != null)
        {
            handler.Invoke(this, EventArgs.Empty);
        }
    }

    public void Destroy()
    {
        this.canExecute = _ => false;
        this.execute = _ => { return; };
    }

    private static bool DefaultCanExecute(object parameter)
    {
        return true;
    }
}

}

and finaly DeviceInformation

    using System;

namespace WpfApplication
{
    public interface IDeviceInformationVM
    {
        string MyProperty { get; set; }
    }

    public class DeviceInformationVM : IDeviceInformationVM
    {
        public string MyProperty
        {
            get; set;
        }
    }
}

Hope it helps