C# WPF MVVM - 将项添加到 VM 实例中的可观察集合时,视图不会更改



描述

我目前正在构建一个应用程序,如果用户在主视图上的组合框上触发了一个事件,它将使用selectedem并将其添加到辅助视图上的ObservableCollection,当用户触发事件添加项目时,它成功地将项目添加到Collection,但不会更新ObservableCollections绑定的ItemsControl中的UI。

问题

当ObservableCollection在另一个ViewModel中添加了一个项时,UI不会更新。

工作列表

JobList派生自ObservableCollection<Job>类型,允许在加载应用程序时使用xml加载稍后存储的数据,它最多有6项。

class JobList : ObservableCollection<Job>
{
public JobList () : base ()
{
if (JobListExists)
LoadExistingJobList();
}
private bool JobListExists
{
get {
bool result = false;
if (File.Exists(recentsPath + @"RecentItems.xml"))
{
result = true;
}
return result;
}
}
private void LoadExistingJobList ()
{
using (var reader = new StreamReader(recentsPath + @"RecentItems.xml"))
{
XmlSerializer deserializer = new XmlSerializer(typeof(List<Job>),
new XmlRootAttribute("Jobs"));
List<Job> jobs = (List<Job>)deserializer.Deserialize(reader);
foreach (Job job in jobs)
{
Add(job);
}
}
}
public void AddToCollection (Job job)
{
Insert(0, job);
if (Count == 7)
RemoveAt(6);
}
}

主视图

MainView用于MainWindow并存储SearchBox(在多个位置使用(和存储CurrentView的ContentControl。当事件从这里发生时,绑定到ContentControl的视图不会发生后续更改。

<Window.DataContext>
<viewModel:MainViewModel/>
</Window.DataContext>
<Border Background="#272537"
CornerRadius="15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>

<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Image Source="/Images/LegIcon.png" Width="30" Height="30" />
<StackPanel Grid.Row="1">
<RadioButton Height="40" Margin="5" Content="/Images/Home.png" Style="{StaticResource MenuButtonTheme}" IsChecked="True" Command="{Binding HomeViewCommand}"/>
<RadioButton Height="40" Margin="5" Content="/Images/Globals.png" Style="{StaticResource MenuButtonTheme}" Command="{Binding GlobalViewCommand}"/>
</StackPanel>
<RadioButton Grid.Row="1" Height="40" Margin="5" Content="/Images/Settings.png" VerticalAlignment="Bottom" Style="{StaticResource MenuButtonTheme}"/>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<ComboBox Width="190"
Height="40"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5"
Grid.Column="1"
Style="{StaticResource SearchBoxTheme}"
ItemsSource="{Binding CurrentDropdownData}"
IsEditable="true"
DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True">
<ComboBox.InputBindings>
<KeyBinding Gesture="Enter"
Command="{Binding SearchBoxCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ComboBox}}}"/>
</ComboBox.InputBindings>
</ComboBox>
<Button Name="MinimizeButton" Style="{StaticResource MinimizeButton}" Margin="5" Width="40" Click="MinimizeButton_Click" />
</StackPanel>
<ContentControl Grid.Row="1"
Grid.Column="1"
Content="{Binding CurrentView}"/>
</Grid>
</Border>

MainViewModel

class MainViewModel : ObservableObject
{
public RelayCommand HomeViewCommand { get; set; }
public RelayCommand GlobalViewCommand { get; set; }
public RelayCommand SearchBoxCommand { get; set; }
public HomeViewModel HomeVM { get; set; }
public GlobalViewModel GlobalVM { get; set; }
private object _currentView;
public object CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
OnPropertyChanged();
}
}
private ICollectionView _currentDropdownData;
public ICollectionView CurrentDropdownData
{ 
get { return _currentDropdownData; }
set
{
_currentDropdownData = value;
OnPropertyChanged("CurrentDropdownData");
}
}
public MainViewModel()
{
CurrentDropdownData = CollectionViewSource.GetDefaultView(DataProvider.GetProjectItems());
HomeVM = new HomeViewModel();
GlobalVM = new GlobalViewModel();
CurrentView = HomeVM;
HomeViewCommand = new RelayCommand(o =>
{
CurrentDropdownData = CollectionViewSource.GetDefaultView(DataProvider.GetProjectItems());
CurrentView = HomeVM;
SearchBoxCommand = new RelayCommand(e =>
{
((HomeViewModel)CurrentView).Collection.AddToCollection((Job)CurrentDropdownData.CurrentItem);
});
});
GlobalViewCommand = new RelayCommand(o =>
{
CurrentDropdownData = CollectionViewSource.GetDefaultView(DataProvider.GetGlobalItems());
CurrentView = GlobalVM;
SearchBoxCommand = new RelayCommand(e =>
{
});
});
SearchBoxCommand = new RelayCommand(e =>
{
((HomeViewModel)CurrentView).Collection.AddToCollection((Job)CurrentDropdownData.CurrentItem);
});
}
}

主页视图

主视图仅使用ItemsControl;集合";JobList作为DataBinding显示当前选择的作业

<UserControl.DataContext>
<viewModel:HomeViewModel/>
</UserControl.DataContext>
<ItemsControl x:Name="TilePanel" ItemsSource="{Binding Collection, Mode=TwoWay}" xmlns:model="clr-namespace:JobMate_2.MVVM.Model">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type model:Job}">
<Border Background="#353340"
CornerRadius="5" 
Margin="5"
Height="50">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="25"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name, Mode=OneWay}"
Foreground="White"
Margin="5"
FontFamily="/Fonts/#Poppins"
x:Name="JobTitle"/>
<Button Grid.Column="1"
Content="."
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Margin="2.5"
Visibility="Hidden"/>
<UniformGrid Columns="3" Grid.Row="1">
<Button Content="Shared" Margin="2.5" Style="{StaticResource FileLocationButton}"/>
<Button Content="Job Data" Margin="2.5" Style="{StaticResource FileLocationButton}"/>
<Button Content="Proc. Data" Margin="2.5" Style="{StaticResource FileLocationButton}"/>
</UniformGrid>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

HomeViewModel

HomeViewModel非常简单地存储视图中正在用于数据绑定的集合。

class HomeViewModel : ObservableObject
{
private JobList _collection;
public JobList Collection
{
get { return _collection; }
set
{
_collection = value;
OnPropertyChanged("Collection");
}
}
public HomeViewModel ()
{
Collection = new JobList()
{
new Job () { Name = "Test" },
new Job () { Name = "Test 2" },
new Job () { Name = "Test 3" }
};
}
}
原因只有一个
在Window和UserControl中有不同的HomeViewModel实例
UserControl不必创建自己的数据上下文
他应该通过绑定到CurrentView从Window中获取它。

如果您在窗口中创建一个UserControl实例,并且MainViewModel位于其数据上下文中,那么您需要这样的绑定:

<UserControl *****
***********
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CurrentView}">
<d:UserControl.DataContext>
<viewModel:HomeViewModel/>
</d:UserControl.DataContext>

最新更新