简体   繁体   English

当绑定列表更新时,WPF ListBox不会更新

[英]WPF ListBox not updating when Bound List is updated

I'm having a problem with my ListBox as it's not updating when I update the list it's bound to. 我的ListBox出现问题,因为更新绑定到的列表时没有更新。 I've already seen many of the same questions but none of it's answers solved my problem. 我已经看过许多相同的问题,但是没有一个答案能解决我的问题。 My situation is that I have a ComboBox that when an option is selected, my ListBox will show options based on the ComboBox selection. 我的情况是我有一个ComboBox,当选择一个选项时,我的ListBox将基于ComboBox选择显示选项。 I know that the list bound to the ListBox is being updated, but the items don't show on the list. 我知道绑定到ListBox的列表正在更新,但是项目没有显示在列表上。 If I manualy add an item on the declaration of the ViewModel class of the list than the item appear, but that's not what I want (or maybe it is and I'm seeing this from the wrong angle). 如果我在列表的ViewModel类的声明上手动添加了一个项目,则该项目的出现比我想的要多,但这不是我想要的(或者也许是我从错误的角度看到的)。 Here's my code so far: 到目前为止,这是我的代码:

The VM for my ComboBox and the calling for updating the ListBox: 我的ComboBox的VM和用于更新ListBox的调用:

public class SelectorEventosViewModel : ObservableCollection<SelectorEvents>,INotifyPropertyChanged
{
    private SelectorEvents _currentSelection;
    public SelectorEventosViewModel()
    {
        PopulaSelectorEvents();
    }

    private void PopulaSelectorEvents()
    {
        Add(new SelectorEvents {Key = "evtInfoEmpregador", Value = "S1000"});
        Add(new SelectorEvents {Key = "evtTabEstab", Value = "S1005"});
        Add(new SelectorEvents {Key = "evtTabRubricas", Value = "S1010"});
    }

    public SelectorEvents CurrentSelection
    {
        get => _currentSelection;
        set
        {
            if (_currentSelection == value)
                return;
            _currentSelection = value;
            OnPropertyChanged(nameof(CurrentSelection));
            ValueChanged(_currentSelection.Key);
        }
    }
    //Here I detect selectiong and then call for the Update in my ListBox VM
    private void ValueChanged(string value)
    {
        EventFilesViewModel.Instance.GetFiles(value);
    }

    protected override event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Here's my code for the ListBox VM: 这是ListBox VM的代码:

public class EventFilesViewModel : ObservableCollection<EventFiles>
{
    private static EventFilesViewModel _instance = new EventFilesViewModel();
    public static EventFilesViewModel Instance => _instance ?? (_instance = new EventFilesViewModel());
    private string[] _filesList;
    //This would be my Update function, based on the ComboBox selection I would show some files in my ListBox, but it's not
    public void GetFiles(string ptr)
    {
        _filesList = Directory.GetFiles(@"\\mp-2624/c$/xampp/htdocs/desenv2/public/esocial/eventos/aguardando/");
        Clear();
        foreach (string file in _filesList)
        {
            var r = new Regex(ptr, RegexOptions.IgnoreCase);
            var tempFiles = new EventFiles {Key = file, Value = file.Split('/')[9]};
            if (r.Match(file).Success)
            {
                Add(tempFiles);
            }
        }
        OnPropertyChanged(nameof(EventFilesViewModel));
    }

    protected override event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

My models SelectorEvents and FileEvents both implement the INotifyPropertyChanged. 我的模型SelectorEvents和FileEvents都实现了INotifyPropertyChanged。

My XAML: 我的XAML:

<ComboBox DataContext="{StaticResource ResourceKey=SelectorEventosViewModel}" Name="EventoBox" FontSize="20" SelectedIndex="0" Margin="20 10" Width="150" 
                                          ItemsSource="{StaticResource ResourceKey=SelectorEventosViewModel}"
                                          DisplayMemberPath="Value"
                                          SelectedItem="{Binding CurrentSelection}"
                                          IsSynchronizedWithCurrentItem="True"/>

<ListBox DataContext="{StaticResource ResourceKey=EventFilesViewModel}"
                                             Grid.Column="0" Name="EventoListBox" FontSize="20" Margin="10 10"
                                             HorizontalAlignment="Stretch"
                                             ItemsSource="{StaticResource ResourceKey=EventFilesViewModel}"
                                             IsSynchronizedWithCurrentItem="True"
                                             DisplayMemberPath="Value">

Thanks in advance. 提前致谢。

So I'm not certain how you intended to have this work, but here's a solution which is more MVVM. 因此,我不确定您打算如何进行这项工作,但是这里有一个解决方案,它是更多的MVVM。

Essentially we collapse both of your VM's into a MainWindowVm, which handles shuttling messages between the two. 本质上,我们将两个VM都折叠到MainWindowVm中,该MainWindowVm处理两者之间的穿梭消息。 That way your child VM's remain independent of each other, and thus more configurable down the line. 这样,您的子VM便保持彼此独立,因此可以在线下进行更多配置。

Based on my testing the binding for your ItemSource on the second record was not succeeding (I added a button and examined the value for ItemSource at run time after confirming the EventFilesViewModel had been updated). 根据我的测试,第二条记录上与ItemSource的绑定未成功(我在确认EventFilesViewModel已更新之后添加了一个按钮,并在运行时检查了ItemSource的值)。

EventFilesViewModel EventFilesViewModel

public class EventFilesViewModel : INotifyPropertyChanged
{
   public ObservableCollection<EventFiles> EventFiles { get; } = new ObservableCollection<EventFiles>();

   private string[] _filesList;

   //This would be my Update function, based on the ComboBox selection I would show some files in my ListBox, but it's not
   public void GetFiles(string ptr)
   {
      _filesList = Directory.GetFiles(@"\\mp-2624/c$/xampp/htdocs/desenv2/public/esocial/eventos/aguardando/");
      EventFiles.Clear();
      foreach (string file in _filesList)
      {
         var r = new Regex(ptr, RegexOptions.IgnoreCase);
         var tempFiles = new EventFiles { Key = file, Value = file.Split('/')[9] };
         if (r.Match(file).Success)
         {
            EventFiles.Add(tempFiles);
         }
      }
      OnPropertyChanged(nameof(EventFilesViewModel));
   }

   public event PropertyChangedEventHandler PropertyChanged;

   [NotifyPropertyChangedInvocator]
   protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }
}

SelectorEventosViewModel SelectorEventosViewModel

public class SelectorEventosViewModel : INotifyPropertyChanged
{
   public ObservableCollection<SelectorEvents> SelectorEvents { get; set; } = new ObservableCollection<SelectorEvents>();

   private SelectorEvents _currentSelection;

   public SelectorEventosViewModel()
   {
      PopulaSelectorEvents();
   }

   private void PopulaSelectorEvents()
   {
      SelectorEvents.Add(new SelectorEvents { Key = "evtInfoEmpregador", Value = "S1000" });
      SelectorEvents.Add(new SelectorEvents { Key = "evtTabEstab", Value = "S1005" });
      SelectorEvents.Add(new SelectorEvents { Key = "evtTabRubricas", Value = "S1010" });
   }

   public SelectorEvents CurrentSelection
   {
      get => _currentSelection;
      set
      {
         if (_currentSelection == value)
            return;

         _currentSelection = value;
         OnPropertyChanged();
      }
   }

   public event PropertyChangedEventHandler PropertyChanged;

   [NotifyPropertyChangedInvocator]
   protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }
}

MainWindowVm.cs MainWindowVm.cs

public class MainWindowVm : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   [NotifyPropertyChangedInvocator]
   protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }

   public SelectorEventosViewModel SelectorEventosViewModel { get; } = new SelectorEventosViewModel();

   public EventFilesViewModel EventFilesViewModel { get; } = new EventFilesViewModel();

   public MainWindowVm()
   {
      // CRITICAL--ensures that your itemsource gets updated
      SelectorEventosViewModel.PropertyChanged += SelectorEventosViewModel_PropertyChanged;
   }

   private void SelectorEventosViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
   {
      // CRITICAL--ensures that your itemsource gets updated
      EventFilesViewModel.GetFiles(SelectorEventosViewModel.CurrentSelection.Key);
   }
}

MainWindow.xaml MainWindow.xaml

<Window x:Class="_52370275.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_52370275"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="450"
        Width="800"
        d:DataContext="{d:DesignInstance local:MainWindowVm}">
   <Grid>
      <Grid.RowDefinitions>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="Auto"/>
         <RowDefinition />
      </Grid.RowDefinitions>
      <ComboBox
         Name="EventoBox"
         FontSize="20"
         SelectedIndex="0"
         Margin="20 10"
         Width="150"
         Grid.Row="0"
         ItemsSource="{Binding SelectorEventosViewModel.SelectorEvents}"
         DisplayMemberPath="Value"
         SelectedItem="{Binding SelectorEventosViewModel.CurrentSelection}"
         IsSynchronizedWithCurrentItem="True" />

      <ListBox Grid.Column="0"
               Name="EventoListBox"
               FontSize="20"
               Margin="10 10"
               Grid.Row="1"
               HorizontalAlignment="Stretch"
               ItemsSource="{Binding EventFilesViewModel.EventFiles}"
               IsSynchronizedWithCurrentItem="True"
               DisplayMemberPath="Value" />
   </Grid>
</Window>

MainWindow.xaml.cs MainWindow.xaml.cs

public partial class MainWindow : Window
{
   public MainWindow()
   {
      InitializeComponent();
      DataContext = new MainWindowVm();
   }
}

All together, this allows you to define the static values for your initial combobox in code-behind, and have the list box itemsource be updated. 总之,这使您可以在代码隐藏中为初始组合框定义静态值,并更新列表框itemsource。

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

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