c# - WPF Bound Editable Combobox 在文本更改时不更改 ID

标签 c# wpf xaml mvvm combobox

我不确定 bind 的正确方法是什么combobox control是我的view model .

我正在使用 MVVM 方法,所以在我的 viewmodel 中我正在加载所有 CDType数据并将其源与实际记录属性结合在一起model.CDType.idmodel.CDType.name .

当我更改文本时会发生什么? - 我保留我的旧 id(来自加载例程)并从组合框绑定(bind)中获取新的文本值,因此始终覆盖现有记录而不是创建新记录。

如果文本不在列表中,如何让我的组合框将 id 设置为 0/undefined? (手动?-有点蹩脚)

任何事情都会有所帮助-谢谢!

TL;DR: 可编辑组合框不会在文本更改时更新 ID。

示例 Xaml 绑定(bind):

<ComboBox x:Name="ddlCDType"    
          IsTextSearchEnabled="True"     
          IsTextSearchCaseSensitive="False"     
          StaysOpenOnEdit="True"    
          TextSearch.TextPath="Name"     
          ItemsSource="{Binding CDTypes}"    
          SelectedValue="{Binding Assignment.CDType.ID}"     
          Text="{Binding Assignment.CDType.Name,     
          UpdateSourceTrigger=PropertyChanged,    
          NotifyOnValidationError=True,     
          ValidatesOnDataErrors=True}"      
          DisplayMemberPath="Name"     
          SelectedValuePath="ID"     
          IsEditable="True"     
          HorizontalAlignment="Left"     
          Margin="98,10,0,0"     
          VerticalAlignment="Top"     
          Width="136" />

最佳答案

据我所知,当手动更改所选 ComboBox 项目的名称并且此名称未出现在 ComboBox ItemSource 中时,您需要更新上一个最后选择的值。这是我的建议,它是您的 ComboBox 控件数据绑定(bind)和 ViewModel 中定义的逻辑的组合。

绑定(bind)说明

  • 由于 ComboBox ItemsSource 是 Cd 的集合(ComboModels 的集合),因此 TextSearch.TextPath binding 应定义为 CDType.Name,其中 CdType 是 ComboModel 中定义的描述子模型的属性,Name 是描述子模型的实际搜索路径。
  • ComboBox Text 属性绑定(bind)到 AssignmentText 属性以在组合失去焦点时触发更新逻辑(如绑定(bind)中定义的那样)。
  • 如您的示例代码中定义的那样,ItemsSource 是微不足道的。
  • 选定的值将更新整个模型(以防我们更改选定的值名称)。
  • 由于 ComboBox ItemsSource 是 Cd 的集合(我们称之为 ComboModel)DisplayMemberPath binding 应定义为 CDType.Name,其中 CdType 是 ComboModel 中定义的描述子模型的属性,Name 是描述子模型的实际搜索路径。

  • Xaml 代码:
            <Grid VerticalAlignment="Bottom">
            <Grid.DataContext>
                <comboBoxWhenNoAnySelectedHelpAttempt:ComboboxDataContext/>
            </Grid.DataContext>
            <StackPanel Orientation="Vertical">
                <ComboBox x:Name="ddlCDType"    
                          IsTextSearchEnabled="True"     
                          IsTextSearchCaseSensitive="False"     
                          StaysOpenOnEdit="True"    
                          TextSearch.TextPath="CDType.Name"
                          Text="{Binding AssignmentText,     
                          UpdateSourceTrigger=LostFocus, Mode=TwoWay,
                          ValidatesOnDataErrors=True}"
                          ItemsSource="{Binding CDTypes}"    
                          SelectedValue="{Binding Assignment}"     
                          DisplayMemberPath="CDType.Name"     
                          IsEditable="True"     
                          HorizontalAlignment="Left"     
                          Margin="98,10,0,0"     
                          VerticalAlignment="Top"     
                          Width="136" />
                <!--added to see changes in updated combo box item-->
                <TextBlock >
                          <Run Text="Name:"/>
                          <Run Text="{Binding Assignment.CDType.Name, UpdateSourceTrigger=PropertyChanged}"></Run>
                          <Run Text="Id:"/>
                          <Run Text="{Binding Assignment.CDType.ID, UpdateSourceTrigger=PropertyChanged}"></Run>
                </TextBlock>
            </StackPanel>
        </Grid>
    

    虚拟机代码
    public class ComboboxDataContext:BaseObservableObject
    {
        private ObservableCollection<ComboModel> _cdTypes;
        private ComboModel _assignment;
        private string _assignmentText;
        private string _lastAcceptedName;
    
    
        public ComboboxDataContext()
        {
            CDTypes = new ObservableCollection<ComboModel>
            {
                new ComboModel
                {
                    CDType = new ComboModelSubModel
                    {
                        Name = "Cd-1",
                        ID = "1",
                    },
                },
                new ComboModel
                {
                    CDType = new ComboModelSubModel
                    {
                        Name = "Cd-2",
                        ID = "2",
                    }
                },
                new ComboModel
                {
                    CDType = new ComboModelSubModel
                    {
                        Name = "Cd-3",
                        ID = "3",
                    },
                },
                new ComboModel
                {
                    CDType = new ComboModelSubModel
                    {
                        Name = "Cd-4",
                        ID = "4",
                    }
                }
            };
            Assignment = CDTypes.FirstOrDefault();
        }
    
        public ObservableCollection<ComboModel> CDTypes
        {
            get { return _cdTypes; }
            set
            {
                _cdTypes = value;
                OnPropertyChanged();
            }
        }
    
        public ComboModel Assignment
        {
            get { return _assignment; }
            set
            {
                if (value == null)
                    _lastAcceptedName = _assignment.CDType.Name;
                _assignment = value;
                OnPropertyChanged();
            }
        }
    
        //on lost focus when edit is done will check and update the last edited value
        public string AssignmentText
        {
            get { return _assignmentText; }
            set
            {
                _assignmentText = value;
                OnPropertyChanged();
                UpDateSourceCollection(AssignmentText);
            }
        }
    
        //will do the the update on combo lost focus to prevent the 
        //annessasary updates (each property change will make a lot of noice in combo)
        private void UpDateSourceCollection(string assignmentText)
        {
            var existingModel = CDTypes.FirstOrDefault(model => model.CDType.Name == assignmentText);
            if (existingModel != null) return;
            if (_lastAcceptedName == null)
            {
                CDTypes.Add(new ComboModel{CDType = new ComboModelSubModel{ID = string.Empty, Name = assignmentText}});
            }
            else
            {
                var existingModelToEdit = CDTypes.FirstOrDefault(model => model.CDType.Name == _lastAcceptedName);
                if(existingModelToEdit == null) return;
                existingModelToEdit.CDType.Name = assignmentText;
                existingModelToEdit.CDType.ID = string.Empty;
            }
    
        }
    }
    
    public class ComboModel:BaseObservableObject
    {
        private ComboModelSubModel _cdType;
    
        public ComboModelSubModel CDType
        {
            get { return _cdType; }
            set
            {
                _cdType = value;
                OnPropertyChanged();
            }
        }
    }
    
    public class ComboModelSubModel:BaseObservableObject
    {
        private string _id;
        private string _name;
    
        public string ID
        {
            get { return _id; }
            set
            {
                _id = value;
                OnPropertyChanged();
            }
        }
    
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChanged();
            }
        }
    }
    

    BaseObservableObject 代码
        /// <summary>`enter code here`
    /// implements the INotifyPropertyChanged (.net 4.5)
    /// </summary>
    public class BaseObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    
        protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
        {
            var propName = ((MemberExpression)raiser.Body).Member.Name;
            OnPropertyChanged(propName);
        }
    
        protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
        {
            if (!EqualityComparer<T>.Default.Equals(field, value))
            {
                field = value;
                OnPropertyChanged(name);
                return true;
            }
            return false;
        }
    }
    

    问候。

    关于c# - WPF Bound Editable Combobox 在文本更改时不更改 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35192416/

    相关文章:

    wpf - 如何将 Popup(或 ContextMenu)的 PlacementTarget 绑定(bind)到 UserControl 中的元素?

    c# - 使用ServiceStack上传图片文件

    c# - Windows Azure 入门

    c# - Xaml 中 Border 元素外部的阴影类似边框

    c# - WPF:ObservableCollection 内存泄漏

    c# - 启动应用程序时 advapi32.dll 中的 EntryPointNotFoundException

    c# - 将静态类添加到 Application.Resources 错误

    c# - XAML 绑定(bind)到另一个元素的对立面

    c# - 使用 BackgroundWorker.Backgroundworker 显示命令提示符输出

    c# - 用户控制自定义事件并设置获取属性