0

I've tried lots of solutions online but I still get this issue. I have a combobox whose item source is a list of customized class. Each element in the source is displayed as a checkbox in the combobox. Now I have a button whose "Click" function is to uncheck all the checkboxes.

The customized class:

    public class LinkObject: INotifyPropertyChanged
    {
        public int index { set; get; }
        public string LO_Name { set; get; }
        private bool _checkStatus { set; get; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void Notify(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public bool checkStatus
        {
            get { return _checkStatus; }
            set
            {
                _checkStatus = value;
                Notify("IsChecked");
            }
        }
    }

The XAML:

<ComboBox Name="cbx1" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="126,82,0,0" VerticalAlignment="Top" Width="50" Height="20" IsEditable="True" IsTextSearchEnabled="True" StaysOpenOnEdit="True" TextBoxBase.TextChanged="cbx1_TextChanged">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Name="cbk1" IsChecked="{Binding checkStatus, Mode=TwoWay}" CommandParameter="{Binding index}" Checked="chk_Checked"  Unchecked="chk_Unchecked">
                <CheckBox.Content>
                    <TextBlock Text="{Binding LO_Name}"/>
                </CheckBox.Content>
            </CheckBox>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Main function by initialization:

cbx1.ItemsSource = LinkObjectsList_cbx1;

LinkObjectsList_cbx1 is a List<LinkObject>.

The button has a name "clearAllTopView", the click function is:

private void clearAllTopViewBtn_Click(object sender, RoutedEventArgs e)
{
    LinkObjectsList_cbx1.Where(l => l.checkStatus == true).ToList().ForEach(lo => lo.checkStatus = false);
}

But when I click the button, nothing happens. Could someone give me a hint or advice? Thank you.

BabyHai
  • 89
  • 1
  • 9
  • This should be checkStatus Notify("IsChecked"); – Andy Apr 20 '21 at 17:27
  • @Andy I did use Notify("IsChecked"). Sorry I fail to get what you mean, would you please explain more to me? Thanks – BabyHai Apr 20 '21 at 18:06
  • Sorry i wasn't clearer. That should be checkstatus you're raising propertychange for. You raise the event with the name of the viewmodel property. The binding source rather than target. – Andy Apr 20 '21 at 18:31
  • Rather than recreate the wheel, you might consider using mvvmlight to handle to propertychanged and notification code, plus it has a nice messenger service as well. – Kevin Cook Apr 20 '21 at 19:42

1 Answers1

1

You have an accidental error due to name confusion. In order not to make such simple but subtle mistakes, I advise you to use a simple base class, but with a better implementation of INPC.

Here is my version of this class. Copy it and include it in your Solution.

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Simplified
{
    /// <summary>Base class with implementation of the <see cref="INotifyPropertyChanged"/> interface.</summary>
    public abstract class BaseInpc : INotifyPropertyChanged
    {
        /// <inheritdoc cref="INotifyPropertyChanged"/>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>The protected method for raising the event <see cref = "PropertyChanged"/>.</summary>
        /// <param name="propertyName">The name of the changed property.
        /// If the value is not specified, the name of the method in which the call was made is used.</param>
        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary> Protected method for assigning a value to a field and raising 
        /// an event <see cref = "PropertyChanged" />. </summary>
        /// <typeparam name = "T"> The type of the field and assigned value. </typeparam>
        /// <param name = "propertyField"> Field reference. </param>
        /// <param name = "newValue"> The value to assign. </param>
        /// <param name = "propertyName"> The name of the changed property.
        /// If no value is specified, then the name of the method 
        /// in which the call was made is used. </param>
        /// <remarks> The method is intended for use in the property setter. <br/>
        /// To check for changes,
        /// used the <see cref = "object.Equals (object, object)" /> method.
        /// If the assigned value is not equivalent to the field value,
        /// then it is assigned to the field. <br/>
        /// After the assignment, an event is created <see cref = "PropertyChanged" />
        /// by calling the method <see cref = "RaisePropertyChanged (string)" />
        /// passing the parameter <paramref name = "propertyName" />. <br/>
        /// After the event is created,
        /// the <see cref = "OnPropertyChanged (string, object, object)" />
        /// method is called. </remarks>
        protected void Set<T>(ref T propertyField, T newValue, [CallerMemberName] string propertyName = null)
        {
            if (!object.Equals(propertyField, newValue))
            {
                T oldValue = propertyField;
                propertyField = newValue;
                RaisePropertyChanged(propertyName);

                OnPropertyChanged(propertyName, oldValue, newValue);
            }
        }

        /// <summary> The protected virtual method is called after the property has been assigned a value and after the event is raised <see cref = "PropertyChanged" />. </summary>
        /// <param name = "propertyName"> The name of the changed property. </param>
        /// <param name = "oldValue"> The old value of the property. </param>
        /// <param name = "newValue"> The new value of the property. </param>
        /// <remarks> Can be overridden in derived classes to respond to property value changes. <br/>
        /// It is recommended to call the base method as the first operator in the overridden method. <br/>
        /// If the overridden method does not call the base class, then an unwanted change in the base class logic is possible. </remarks>
        protected virtual void OnPropertyChanged(string propertyName, object oldValue, object newValue) { }
    }
}

With this basic implementation, your entity class will have code like this:

using Simplified;

namespace Febr20y
{
    public class LinkObject : BaseInpc
    {
        public int Index { set; get; }
        public string LO_Name { set; get; }
        private bool _checkStatus;

       public bool CheckStatus { get => _checkStatus; set => Set(ref _checkStatus, value); }
    }
}

This is not relevant to your question, but I advise you to follow the Naming Guidelines. Namely, property names must begin with the Upper letter.

GregC
  • 7,737
  • 2
  • 53
  • 67
EldHasp
  • 6,079
  • 2
  • 9
  • 24
  • 1
    I deleted the previous reply because I made a stupid mistake. Thank you very much for you help, it totally works now. – BabyHai Apr 20 '21 at 18:33