如何解决C# WPF MVVM - 当项目添加到 VM 实例中的 ObservableCollection 时,视图不会改变
说明
我目前正在构建一个应用程序,如果用户在主视图上找到的组合框上触发事件,它将获取所选项目并将其添加到辅助视图上的 ObservableCollection,当用户触发事件添加项,它成功地将其添加到集合中,但不会更新 ObservableCollection 绑定的 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>
主视图模型
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);
});
}
}
主页视图
Home View 仅使用 ItemsControl 将“Collections”JobList 引用为 DataBinding 来显示当前选定的 Jobs
<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 获取它。
如果您在其数据上下文中使用 MainViewModel 在 Window 中创建 UserControl 的实例,那么您需要这样的绑定:
<UserControl *****
***********
DataContext="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.CurrentView}">
<d:UserControl.DataContext>
<viewModel:HomeViewModel/>
</d:UserControl.DataContext>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。