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

时间:2018-09-17 14:41:27

标签: c# wpf mvvm data-binding

我的列表框有问题,因为更新绑定到的列表时它没有更新。我已经看过许多相同的问题,但是没有一个答案能解决我的问题。我的情况是我有一个ComboBox,当选择一个选项时,我的ListBox将基于ComboBox选择显示选项。我知道绑定到ListBox的列表正在更新,但是项目没有显示在列表上。如果我在列表的ViewModel类的声明上手动添加了一个项目,则该项目的出现比我想的要多,但这不是我想要的(或者也许是我从错误的角度看到的)。到目前为止,这是我的代码:

用于我的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));
    }
}

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

我的模型SelectorEvents和FileEvents都实现了INotifyPropertyChanged。

我的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">

谢谢。

1 个答案:

答案 0 :(得分:0)

所以我不确定您打算如何进行这项工作,但是这里有一个解决方案,它是更多的MVVM。

实质上,我们将两个VM都折叠到MainWindowVm中,该MainWindowVm处理两者之间的穿梭消息。这样,您的子虚拟机就可以保持彼此独立,从而可以在线下进行更多配置。

根据我的测试,第二条记录上与ItemSource的绑定未成功(我在确认EventFilesViewModel已更新之后添加了一个按钮,并在运行时检查了ItemSource的值)。

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

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

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

<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

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

总而言之,这使您可以在代码后方为初始组合框定义静态值,并更新列表框itemsource。