WPF绑定可编辑组合框不更改文本更改时的ID

时间:2016-02-04 04:17:13

标签: c# wpf xaml mvvm combobox

我不确定bindcombobox control view model的正确方法是什么。

我正在使用MVVM方法,所以在我的viewmodel我正在加载所有CDType数据,并将其源与实际记录属性model.CDType.id和{{绑定在一起1}}。

当我更改文本时会发生什么? - 我保留旧ID(来自加载例程)并从组合框绑定中获取新文本值,因此总是在现有记录上写入创建一个新的。

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

一切都会有所帮助 - 谢谢!

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

示例Xaml绑定:

model.CDType.name

1 个答案:

答案 0 :(得分:0)

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

绑定说明

  1. 由于ComboBox ItemsSource是Cd(ComboModels的集合)的集合,因此TextSearch.TextPath绑定应定义为CDType.Name,其中CdType是在描述子模型的ComboModel中定义的属性,并且名称是描述子模型的实际搜索路径。
  2. ComboBox Text属性绑定到AssignmentText属性,以在组合丢失焦点时触发更新逻辑(如绑定中所定义)。
  3. 您的示例代码中定义的ItemsSource是微不足道的。
  4. 选定的值将使整个模型更新(如果我们更改所选的值名称)。
  5. 由于ComboBox ItemsSource是Cd的集合(我们称之为ComboModel),DisplayMemberPath绑定应定义为CDType.Name,其中CdType是描述子模型的ComboModel中定义的属性,名称是描述子模型的实际搜索路径。
  6. 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;
        }
    }
    

    问候。