Выбранный элемент в выпадающем списке не меняет своего значения после обновления веб-службы

У меня есть пользовательский элемент управления WPF, который содержит поле со списком:

<UserControl
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="Hartville.SalesScriptApplication.Views.SalesScriptEditorGroups" 
             mc:Ignorable="d" 
         xmlns:events="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
             xmlns:hartvm="clr-namespace:Hartville.SalesScript.ViewModels;assembly=Hartville.SalesScript.ViewModels"
             d:DesignHeight="106" d:DesignWidth="909" Background="#FFF3EDED">
    <UserControl.Resources>
        <ResourceDictionary>
            <hartvm:ViewLocator x:Key="HartvilleLocator" d:IsDataSource="True" />
        </ResourceDictionary>
    </UserControl.Resources>
    <UserControl.DataContext>
        <Binding Source="{StaticResource HartvilleLocator}" Path="ScriptEditorGroups" />
    </UserControl.DataContext>
    <Border>
        <Grid Margin="5,10,0,20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal" Margin="0,10,0,20">
                <TextBlock TextWrapping="Wrap" Text="Selected Script Group:"/>
                <ComboBox Width="250" Margin="10,0,0,0" HorizontalAlignment="Left" ItemsSource="{Binding ScriptGroups}" SelectedItem="{Binding SelectedScriptGroup}" 
                    DisplayMemberPath="Name" >
                    <events:Interaction.Triggers>
                        <events:EventTrigger EventName="SelectionChanged">
                            <cmd:EventToCommand Command="{Binding ScriptGroupSelectedCommand}" PassEventArgsToCommand="False" />
                        </events:EventTrigger>
                    </events:Interaction.Triggers>              
                </ComboBox>
            </StackPanel>
    </Border>
</UserControl>

ПРИМЕЧАНИЕ: мы используем легкие рамки MVVM. Локатор представлений, который вы видите, является просто классом, который создает модель представления, на которую вы будете ссылаться в части контекста данных.

Когда что-то выбрано из поля со списком и нажата кнопка редактирования, пользователь может обновить имя и сохранить его. Тем не менее, когда пользователь нажимает кнопку Сохранить, вы можете увидеть измененный выбор в комбинированном списке, но выбранный элемент по-прежнему содержит исходное имя. Так, например, я выбираю опцию "Hello World" из поля со списком. Я меняю имя на "FOOBAR" и нажимаю "Сохранить". Я обновляю выбранный элемент в коде (и вижу, что свойство меняется). Когда я проверяю поле со списком, я вижу "FOOBAR", но выбранное значение по-прежнему говорит "Hello World". Кроме того, "Hello World" больше не существует в выпадающем списке (очевидно, потому что я только что обновил его.

Вот код для модели представления:

using System.Windows.Input;
using System.Collections.ObjectModel;
using GalaSoft.MvvmLight.Command;
using Hartville.Common.Controls.ViewModels;
using Hartville.Common.Controls.ViewModels.Validation;
using Hartville.SalesScript.ViewModels.Messages;
using Hartville.Values.Sales;
using System.Linq;

namespace Hartville.SalesScript.ViewModels.Scripts
{
    public class ScriptEditorGroups: CommonViewModelBase
    {
        private ObservableCollection<ScriptHeader> _scriptGroups;
        private ObservableCollection<Script> _scripts; 
        private ScriptHeader _selectedScriptGroup;
        private Script _selectedScript;
        private bool _isScriptGroupActive;
        private string _groupName;
        private bool _shouldEnableScriptGroup;
        private bool _shouldShowGroupEditPanel;
        private bool _shouldUseDefaultScript;
        private bool _shouldShowScriptSelection;

        public ICommand EditSelectedCommand { get; set; }
        public ICommand NewGroupCommand { get; set; }
        public ICommand SaveCommand { get; set; }
        public ICommand ScriptGroupSelectedCommand { get; set; }

        public ObservableCollection<ScriptHeader> ScriptGroups
        {
            get { return _scriptGroups; }
            set { SetPropertyValue(ref _scriptGroups, value); }
        }

        public ObservableCollection<Script> Scripts
        {
            get { return _scripts; }
            set { SetPropertyValue(ref _scripts, value); }
        }

        public ScriptHeader SelectedScriptGroup
        {
            get { return _selectedScriptGroup; }
            set { SetPropertyValue(ref _selectedScriptGroup, value ); }
        }

        public Script SelectedScript
        {
            get { return _selectedScript; }
            set { SetPropertyValue(ref _selectedScript, value); }
        }

        public bool IsScriptGroupActive
        {
            get { return _isScriptGroupActive; }
            set { SetStructPropertyValue(ref _isScriptGroupActive, value); }
        }

        public string GroupName
        {
            get { return _groupName; }
            set { SetStructPropertyValue(ref _groupName, value); }
        }

        public bool ShouldEnableScriptGroup
        {
            get { return _shouldEnableScriptGroup; }
            set { SetStructPropertyValue(ref _shouldEnableScriptGroup, value); }
        }

        public bool ShouldShowGroupEditPanel
        {
            get { return _shouldShowGroupEditPanel; }
            set { SetStructPropertyValue(ref _shouldShowGroupEditPanel, value); }
        }

        public bool ShouldUseDefaultScript
        {
            get { return _shouldUseDefaultScript; }
            set { SetStructPropertyValue(ref _shouldUseDefaultScript, value); }
        }

        public bool ShouldShowScriptSelection
        {
            get { return _shouldShowScriptSelection; }
            set { SetStructPropertyValue(ref _shouldShowScriptSelection, value); }
        }

        public bool IsEdit { get; set; }
        public bool IsNew { get; set; }

        protected override void RegisterForMessages()
        {
            MessengerService.Register<BeginSalesScriptEditorMessage>(OnBeginSalesScriptEditor);

            EditSelectedCommand = new RelayCommand(OnEdit);
            NewGroupCommand = new RelayCommand(OnNewGroup);
            SaveCommand = new RelayCommand(OnSave);
            ScriptGroupSelectedCommand = new RelayCommand(OnScriptGroupSelected);
        }

        private void OnBeginSalesScriptEditor(BeginSalesScriptEditorMessage message)
        {
            ScriptGroups = new ObservableCollection<ScriptHeader>(SalesService.GetAllScriptHeader());
            Scripts = new ObservableCollection<Script>(SalesScriptCache.Scripts);

            ShouldEnableScriptGroup = false;
            ShouldShowGroupEditPanel = false;
            ShouldShowScriptSelection = false;
            IsEdit = false;
            IsNew = false;
        }

        private void OnEdit()
        {
            if(SelectedScriptGroup == null) return;

            IsEdit = true;
            ShouldShowGroupEditPanel = true;
            ShouldShowScriptSelection = true;
            GroupName = SelectedScriptGroup.Name;
            SelectedScript = SalesScriptCache.Scripts.FirstOrDefault(s => s.ScriptId == SelectedScriptGroup.StartScriptId);
        }

        private void OnNewGroup()
        {
            IsNew = true;
            GroupName = string.Empty;
            ShouldShowGroupEditPanel = true;
            ShouldShowScriptSelection = false;
        }

        private void OnSave()
        {
            ThreadManagement.ExecuteInSeparateThread(ProcessScriptUpdate);
        }

        private void OnScriptGroupSelected()
        {
            if(SelectedScriptGroup == null) return;

            MessengerService.Send(ScriptHeaderSelectedMessage.Create(SelectedScriptGroup));
            ShouldEnableScriptGroup = true;
        }

        protected override void SetDesignTimeInfo(){}

        protected void ResetValues()
        {
            ShouldEnableScriptGroup = false;
            ShouldShowGroupEditPanel = false;
            IsScriptGroupActive = false;
            IsEdit = false;
            IsNew = false;
            ShouldShowScriptSelection = false;
        }

        private int CreateNewScriptGroup()
        {
            var scriptHeader = new ScriptHeader
                                   {
                                       Name = GroupName,
                                       IsActive = IsScriptGroupActive
                                   };

            MessengerService.Send(ScriptHeaderSelectedMessage.Create(scriptHeader));
            return SalesService.ScriptHeaderInsertUpdate(scriptHeader);
        }

        private int EditExistingScriptGroup()
        {
            if(SelectedScriptGroup == null) return 0;

            var scriptHeader = new ScriptHeader
                                   {
                                       Name = GroupName,
                                       IsActive = IsScriptGroupActive,
                                       ScriptHeaderId = SelectedScriptGroup.ScriptHeaderId,
                                       StartScriptId = SelectedScript.ScriptId
                                   };

            MessengerService.Send(ScriptHeaderSelectedMessage.Create(scriptHeader));
            return SalesService.ScriptHeaderInsertUpdate(scriptHeader);
        }

        private void ProcessScriptUpdate()
        {
            var returnId = 0;

            if (IsNew)
                returnId = CreateNewScriptGroup();
            else if (IsEdit)
                returnId = EditExistingScriptGroup();

            ScriptGroups = new ObservableCollection<ScriptHeader>(SalesService.GetAllScriptHeader());
            SelectedScriptGroup = ScriptGroups.FirstOrDefault(h => h.ScriptHeaderId == returnId);

            ResetValues();
        }
    }
}

Как мне исправить эту проблему?

РЕДАКТИРОВАТЬ:

Это метод SetPropertyValue, который вызывает уведомление:

public virtual void SetPropertyValue<T>(ref T currentValue, T newValue, Action<T> extraFunction = null, Action voidAfterSetAction = null) where T : class
        {
            if (currentValue == newValue) return;

            currentValue = newValue;

            PropertyHasChanged();

            if (extraFunction != null) extraFunction(newValue);

            if (voidAfterSetAction != null) voidAfterSetAction();
        }

РЕДАКТИРОВАТЬ:

Это весь базовый класс, который содержит код изменения свойства:

using System;
using System.ComponentModel;
using System.Diagnostics;
using GalaSoft.MvvmLight;
using Hartville.Common.Controls.Messaging;
using Hartville.Common.Controls.Modules;
using Hartville.Common.Controls.ViewModels.Validation;
using Hartville.Common.Controls.WebServices;
using Hartville.Common.Threading;

namespace Hartville.Common.Controls.ViewModels
{
    public abstract class CommonViewModelBase : ViewModelBase, IDataErrorInfo
    {


        public string this[string columnName]
        {
            get
            {
                var validationReturn = ValidationManager.Validate(columnName);

                OnValidationComplete();

                return validationReturn;
            }
        }

        public string Error
        {
            get { return null; }
        }

        protected CommonViewModelBase()
        {
            ValidationManager = ValidationManager.Start(this);

            RegisterForMessages();

            if (IsInDesignMode) SetDesignTimeInfo();
        }

        public virtual void Reset()
        {
            IsProcessing = false;
        }

        public virtual void OnValidationComplete()
        {
        }

        public virtual void SetPropertyValue<T>(ref T currentValue, T newValue, Action<T> extraFunction = null, Action voidAfterSetAction = null) where T : class
        {
            if (currentValue == newValue) return;

            currentValue = newValue;

            PropertyHasChanged();

            if (extraFunction != null) extraFunction(newValue);

            if (voidAfterSetAction != null) voidAfterSetAction();
        }

        public virtual void SetPropertyValue<T>(ref T currentValue, T newValue, Action extraFunction) where T : class
        {
            if (currentValue == newValue) return;

            currentValue = newValue;

            PropertyHasChanged();

            if (extraFunction != null) extraFunction();
        }

        public virtual void SetStructPropertyValue<T>(ref T currentValue, T newValue, Action<T> extraFunction = null, Action voidActionAfterSetAction = null)
        {
            currentValue = newValue;

            PropertyHasChanged();

            if (extraFunction != null) extraFunction(newValue);

            if (voidActionAfterSetAction != null) voidActionAfterSetAction();
        }

        public virtual void SetStructPropertyValue<T>(ref T currentValue, T newValue, Action extraFunction)
        {
            currentValue = newValue;

            PropertyHasChanged();

            if (extraFunction != null) extraFunction();
        }

        public virtual void SetValue<T>(ref T currentValue, T newValue, Action<T> voidOldValueAction = null, Action voidAfterSetAction = null) where T : class
        {
            var oldVal = currentValue;

            if (currentValue == newValue) return;

            currentValue = newValue;

            PropertyHasChanged();

            if (voidOldValueAction != null) voidOldValueAction(oldVal);

            if (voidAfterSetAction != null) voidAfterSetAction();
        }

        protected abstract void RegisterForMessages();
        protected abstract void SetDesignTimeInfo();

        protected void SendModalCloseMessage()
        {
            MessengerService.Send(ModalCommandMessage.Create(ModalOptions.Close));
        }

        protected void SendModalOpenMessage(ModalName windowName, Guid? customID = null)
        {
            MessengerService.Send(ModalCommandMessage.Create(ModalOptions.Open, windowName, customID));
        }

        private void PropertyHasChanged()
        {
            var currentFrame = 2;

            var frame = new StackFrame(currentFrame);

            var propertyName = string.Empty;

            if (frame.GetMethod().Name.Length > 4) propertyName = GetPropertyName(frame);

            while (!frame.GetMethod().Name.StartsWith("set_"))
            {
                currentFrame++;

                frame = new StackFrame(currentFrame);

                if (frame.GetMethod().Name.Length > 4) propertyName = GetPropertyName(frame);
            }

            RaisePropertyChanged(propertyName);
        }

        private static string GetPropertyName(StackFrame frame)
        {
            return frame.GetMethod().Name.Substring(4);
        }
    }
}

2 ответа

Вам нужно реализовать iNotifyPropertyChanged и вызвать PropertyChanged в

    public ScriptHeader SelectedScriptGroup 
    { 
        set { SetPropertyValue(ref _selectedScriptGroup, value ); } 
    } 

В дополнение к тому, что Blam уже упомянул, вы должны реализовать интерфейс INotifyPropertyChanged в вашей CommonViewModelBase или текущей модели представления. И вы должны вызвать метод PropertyChanged для всех установщиков свойств, значения которых вы изменяете после того, как Datacontext был назначен представлению.

public ScriptHeader ScriptGroups
{ 
    set { SetPropertyValue(ref _selectedScriptGroup, value ); 
          PropertyChanged("SelectedScriptGroup ");
        } 
}

public ScriptHeader SelectedScriptGroup 
{ 
    set { SetPropertyValue(ref _selectedScriptGroup, value ); 
          PropertyChanged("SelectedScriptGroup");
        } 
}

Иначе, ваш View не сможет узнать, что значение свойства, к которому привязан элемент управления, изменилось. Для реализации, пожалуйста, обратитесь к Свойству Измененная реализация

Другие вопросы по тегам