简体   繁体   English

Web Service更新后,组合框中的“选定项目”未更改其值

[英]Selected Item in combobox is not changing its value after Web Service update

I have a WPF user control that contains a combo box: 我有一个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>

NOTE: We are using MVVM light framework. 注意:我们正在使用MVVM light框架。 The view locator that you see is just a class that instantiates the view model which you will see referenced in the data context portion. 您看到的视图定位器只是一个实例化视图模型的类,您将在数据上下文部分中看到该视图模型。

When something is selected from the combo box and the edit button is clicked, the user can update the name and save it. 从组合框中选择某项并单击“编辑”按钮时,用户可以更新名称并保存。 However, when the user clicks save, you can see the changed selection in the combobox but the selected item still contains the original name. 但是,当用户单击“保存”时,您可以在组合框中看到更改的选择,但是所选项目仍包含原始名称。 So, for example, I select the option "Hello World" from the combo box. 因此,例如,我从组合框中选择选项“ Hello World”。 I change the name to "FOOBAR" and click save. 我将名称更改为“ FOOBAR”,然后单击“保存”。 I update the selected item in the code (and I can see that the property is changing). 我更新了代码中的所选项目(并且我可以看到该属性正在更改)。 When I check the combo box I see "FOOBAR" but the selected value still says "Hello World". 当我选中组合框时,我看到“ FOOBAR”,但所选值仍然显示“ Hello World”。 Also, "Hello World" no longer exists in the combobox (obviously because I just updated it. 而且,“ Hello World”在组合框中不再存在(显然是因为我刚刚对其进行了更新。

Here is the code for the view model: 这是视图模型的代码:

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

How do I fix this issue? 如何解决此问题?

EDIT: 编辑:

This is the SetPropertyValue method that calls the notify: 这是SetPropertyValue方法,该方法调用notify:

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

EDIT: 编辑:

This is the entire base class that holds the property change code: 这是保存属性更改代码的整个基类:

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

You need to implement iNotifyPropertyChanged and call PropertyChanged in 您需要实现iNotifyPropertyChanged并在其中调用PropertyChanged

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

Adding to what Blam has already mentioned, you must implement INotifyPropertyChanged interface in your CommonViewModelBase or current view model. 除了Blam已经提到的内容之外,您还必须在CommonViewModelBase或当前视图模型中实现INotifyPropertyChanged接口。 And you should call the PropertyChanged method for all the property setters whose values you are changing after the Datacontext has been assigned to the view. 并且,应该在将数据上下文分配给视图之后,为要更改其值的所有属性设置器调用PropertyChanged方法。

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

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

Else, there is no way for your View to know that the property value to which the control is binding has changed. 否则,您的视图无法知道控件绑定到的属性值已更改。 For implementation, please refer to Property Changed Implementation 有关实施,请参阅属性更改实施

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM