Выбранный элемент списка со списком не обновляется

#c# #wpf #data-binding

#c# #wpf #привязка данных

Вопрос:

Проблема

Я пытаюсь привязать список SelectedItem со списком к пользовательскому классу, но он не обновляется при изменении свойства. INotifyPropertyChanged .

DataContext

Это DataContext пользовательский класс, который содержит много свойств, но выдержка из него приведена ниже. Вы можете видеть, что он реализует INotifyPropertyChanged , и это вызывается при изменении двух свойств.

 public class BctsChange : INotifyPropertyChanged
{
    #region declarations
    private byContact _Engineer;

    public byContact Engineer
    {
        get { return _Engineer; }
        set
        {
            _Engineer = value;
            NotifyPropertyChanged("Engineer");
            OnEngineerChanged();
        }
    }

    private BctsSvc.DOSets _LeadingSet;

    public BctsSvc.DOSets LeadingSet
    {
        get { return _LeadingSet; }
        set { _LeadingSet = value; NotifyPropertyChanged("LeadingSet"); }
    }
    #endregion

    #region INotify
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    public BctsChange()
    {
        Engineer = new byContact(Environment.UserName);
    }

    private void OnEngineerChanged()
    {
        if (Engineer != null)
        {
            BctsSvc.DOSets leadSet = GetLeadingSetFromDeptCode(Engineer.DeptCode);

            if (leadSet == null) return;
            LeadingSet = leadSet;
        }
    }


    private static BctsSvc.DOSets GetLeadingSetFromDeptCode(string DeptCode)
    {
        BctsSvc.BctsServiceSoapClient svc = new BctsSvc.BctsServiceSoapClient();
        BctsSvc.DOSets setX = svc.GetSetFromDeptCode(DeptCode);
        return setX;
    }
}
  

Окно XAML

У меня есть несколько элементов управления в окне, но для простоты кода, я полагаю, будет достаточно следующего извлечения.

 <Window x:Class="MyNamespace.wdSubmit"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:MyNamespace"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            x:Name="ucReqForm"
        Title="wdSubmit" >
    <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">        
        <GroupBox Header="Engineer Details" Name="grpOwnerDetails" >
            <StackPanel Orientation="Vertical">
                <Grid VerticalAlignment="Top">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="35"/>
                    </Grid.ColumnDefinitions>
                    <Label Content="{Binding Engineer.FullName,  FallbackValue='Please select an engineer by clicking →', Mode=OneWay}" Margin="5,0" IsEnabled="True" FontStyle="Italic" />
                    <Button Content="{StaticResource icoSearch}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="1" Height="23" Name="btnSelectEngineer" Margin="0,0,5,0" HorizontalAlignment="Stretch" ToolTip="Search for an engineer responsible" Click="btnSelectEngineer_Click" />
                </Grid>

                <ComboBox Height="23" x:Name="ddSet2" Margin="5,0" ItemsSource="{Binding LeadingSets, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" SelectedItem="{Binding LeadingSet, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=True}" >
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding SetName}" ToolTip="{Binding HelpInfo}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
                <my:LabelledDropdown Height="23" x:Name="ddSet" Margin="5,0" ItemsSource="{Binding LeadingSets, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" SelectedItem="{Binding LeadingSet, Mode=TwoWay,NotifyOnTargetUpdated=True,NotifyOnSourceUpdated=True}" Label="e.g. BodyHardware">
                    <my:LabelledDropdown.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding SetName}" ToolTip="{Binding HelpInfo}"/>
                        </DataTemplate>
                    </my:LabelledDropdown.ItemTemplate>
                </my:LabelledDropdown>
            </StackPanel>
        </GroupBox>
    </StackPanel>
</Window>
  

Приведенный выше отрывок содержит:

  • A Label , который содержит имя контакта и кнопку для поиска контакта, привязанную к FullName Engineer
  • A ComboBox , содержащий отделы внутри компании, привязанный к an ObservableCollection<DOSets> , который содержит список отделов
  • Два ComboBox параметра, один из которых является пользовательским, а другой — временным, чтобы гарантировать, что ошибка не находится в пределах контроля. Они привязаны к данным LeadingSet

Код окна позади

В исходном коде я установил значение DataContext CurrentChange равным . Когда пользователь захочет выбрать другой Engineer , это обновит выбранный отдел для инженера CurrentChange .

Когда пользователь меняет инженера, привязка данных для инженера обновляется, но выбранный отдел (ведущий набор) — нет.

 //Usings here

namespace MyNamespace
{
    public partial class wdSubmit : Window, INotifyPropertyChanged
    {
        private BctsSvc.BctsServiceSoapClient svc;

        private BctsChange _CurrentChange;

        public BctsChange CurrentChange
        {
            get { return _CurrentChange; }
            set { _CurrentChange = value; OnPropertyChanged("CurrentChange"); }
        }


        private List<BctsSvc.DOSets> _LeadingSets;
        public List<BctsSvc.DOSets> LeadingSets
        {
            get
            {
                return _LeadingSets;
            }
        }


        public wdSubmit()
        {
            InitializeComponent();
            svc = new BctsSvc.BctsServiceSoapClient();
            _LeadingSets = svc.GetLeadSets().ToList();
            OnPropertyChanged("LeadingSets");

            this._CurrentChange = new BctsChange();

            this.DataContext = CurrentChange;

            CurrentChange.PropertyChanged  = new PropertyChangedEventHandler(CurrentChange_PropertyChanged);
        }

        void CurrentChange_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged("CurrentChange");
            OnPropertyChanged(e.PropertyName);
        }

        private void btnSelectEngineer_Click(object sender, RoutedEventArgs e)
        {
            byContact newContact = new frmSearchEngineer().ShowSearch();

            if (newContact != null)
            {
                CurrentChange.Engineer = newContact;
                PropertyChanged(CurrentChange, new PropertyChangedEventArgs("LeadingSet"));
                PropertyChanged(CurrentChange.LeadingSet, new PropertyChangedEventArgs("LeadingSet"));

            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(CurrentChange, new PropertyChangedEventArgs(propertyName));
        }
    }
}
  

Ответ №1:

Я понял, что проблема может быть связана с LeadingSet тем, что, возвращаемый при смене инженера, является экземпляром, отличным от экземпляра в ObservableCollection .

Комментарии:

1. Я не думаю, что это ответ. Но вы можете попробовать это : LeadingSet = LeadingSets.Where(x=> x.Property==leadSet.Property).FirstOrDefault();

2. Попробуйте добавить IsSynchronizedWithCurrentItem="True" в свой список свойств