WPF 双向绑定不适用于组合框中的复选框

Posted

技术标签:

【中文标题】WPF 双向绑定不适用于组合框中的复选框【英文标题】:WPF two-way binding does not work for checkboxes inside a combobox 【发布时间】:2021-07-14 21:51:38 【问题描述】:

我已经在网上尝试了很多解决方案,但我仍然遇到这个问题。 我有一个组合框,其项目源是自定义类的列表。源中的每个元素都显示为组合框中的复选框。现在我有一个按钮,其"Click" 功能是取消选中所有复选框。

自定义类:

    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");
            
        
    

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>

初始化的主函数:

cbx1.ItemsSource = LinkObjectsList_cbx1;

LinkObjectsList_cbx1List&lt;LinkObject&gt;

按钮有一个名字“clearAllTopView”,点击功能是:

private void clearAllTopViewBtn_Click(object sender, RoutedEventArgs e)

    LinkObjectsList_cbx1.Where(l => l.checkStatus == true).ToList().ForEach(lo => lo.checkStatus = false);

但是当我点击按钮时,什么也没有发生。有人可以给我一个提示或建议吗?谢谢。

【问题讨论】:

这应该是 checkStatus Notify("IsChecked"); @Andy 我确实使用了 Notify("IsChecked")。对不起,我没能明白你的意思,你能再解释一下吗?谢谢 对不起,我没说清楚。那应该是您为其提高 propertychange 的检查状态。您使用 viewmodel 属性的名称引发事件。绑定源而不是目标。 您可以考虑使用 mvvmlight 来处理 propertychanged 和通知代码,而不是重新创建***,而且它还有一个很好的消息服务。 【参考方案1】:

由于名称混淆,您遇到了一个意外错误。 为了不犯这种简单但微妙的错误,我建议你使用一个简单的基类,但更好地实现INPC

这是我的这个类的版本。 复制它并将其包含在您的解决方案中。

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 = "propertyFiled"> 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 propertyFiled, T newValue, [CallerMemberName] string propertyName = null)
        
            if (!object.Equals(propertyFiled, newValue))
            
                T oldValue = propertyFiled;
                propertyFiled = 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)  
    

有了这个基本的实现,你的实体类就会有这样的代码:

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); 
    

这与您的问题无关,但我建议您遵循命名指南。 即,属性名称必须以大写字母开头。

【讨论】:

我删除了之前的回复,因为我犯了一个愚蠢的错误。非常感谢您的帮助,现在完全可以使用了。

以上是关于WPF 双向绑定不适用于组合框中的复选框的主要内容,如果未能解决你的问题,请参考以下文章

wpf 4.0 datagrid模板列双向绑定问题

如何在双向绑定组合框(WPF)上调用异步操作

DataGridCheckboxColumn 双向绑定

textarea 双向绑定不适用于 ng-model

WPF双向绑定不起作用

如何修复 WPF Datagrids 中的“双向绑定需要路径或 XPath”异常?