賞金將在 5 天后到期。此問題的答案有資格獲得 50聲望賞金。 aberforth想引起對這個問題的更多關注。
我正在學習 WPF MVVM 模式。我一直在關注 YT 上的 Sean Singleton 教程,到目前為止,我已經理解并設法將這種模式應用到我的應用程式中。
但是有一個方面我不明白發生了什么......
我有一個Binding必須ObservableCollection打開的 ListBox 視圖ViewModel。ViewModel 繼承自ViewModelBasewhich 又引入 ' NotifyPropertyChanged。
肖恩做了一些方法來更新集合,首先清除它,然后再次獲取所有值......當然作為 ObservableCollection 我應該能夠添加一個專案并且它應該通知 UI 某些東西已經改變?
所以到目前為止我所擁有的(為了更好的可讀性,洗掉了不必要的代碼)
看法
<Grid Grid.Row="1" Background="#FFE5E5E5" Margin="0,0,0,0">
<ListView Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="10 10" BorderBrush="{StaticResource DHLYellow}" BorderThickness="1" ItemsSource="{Binding Bookings}">
視圖模型庫
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GIO.UI.ViewModels
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
BookingListingViewModel
using GIO.Interfaces;
using GIO.Services;
using GIO.UI.Commands;
using GIO.UI.Stores;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace GIO.UI.ViewModels
{
public class BookingListingViewModel : ViewModelBase
{
private ObservableCollection<BookingViewModel> _bookings;
private readonly NavigationStore _navigationStore;
public ViewModelBase CurrentViewModel => _navigationStore.CurrentViewModel;
public IEnumerable<BookingViewModel> Bookings => _bookings;
public ICommand CreateBookingCommand { get; }
public BookingListingViewModel(NavigationStore navigationStore)
{
_bookings = new ObservableCollection<BookingViewModel>();
var bookings = BookingService.GetBookings(b => true, b => new BookingViewModel()
{
CustomerReference = b.CustomerRef,
Status = b.BookingStatus.Name,
WindowStart = b.BookingWindowFrom,
WindowEnd = b.BookingWindowTo,
DriverName = b.Driver.Name,
TrailerName = b.Trailer.Name,
VehicleRegPlate = b.Vehicle.RegPlate,
HaulierName = b.Haulier.Name
});
foreach( BookingViewModel b in bookings)
{
_bookings.Add(b);
}
CreateBookingCommand = new NavigateCommand(navigationStore, new CreateBookingViewModel(navigationStore, this));
_navigationStore = navigationStore;
}
public void AddBooking(BookingViewModel booking) //Command would call this method
{
_bookings.Add(booking); //Doesn't update the ListBox on UI
OnPropertyChanged(nameof(Bookings)); // Not in Sean's tutorial. I added that code to try to trigger the notify but it doesn't work
//UpdateBookings(); //Sean's code. It works but it doesn't do anything special other than clear collection and add items.
}
private void UpdateBookings()
{
_bookings.Clear();
foreach (BookingViewModel b in BookingService.GetBookings(b => true, b => new BookingViewModel()
{
CustomerReference = b.CustomerRef,
WindowStart = b.BookingWindowFrom,
WindowEnd = b.BookingWindowTo,
DriverName = b.Driver.Name,
VehicleRegPlate = b.Vehicle.RegPlate,
TrailerName = b.Trailer.Name,
HaulierName = b.Haulier.Name
}))
{
_bookings.Add(b);
}
}
}
}
所以我很困惑為什么我的 ListBox 沒有更新......我該怎么做才能讓它更新,這樣我就不需要清除集合并再次更新?
還有為什么 simple_bookings.Add(booking);不更新 ListBox 但
_bookings.Clear();
_bookings.Add(b);
做?
編輯
可能要指出的一件事是,我正在AddBooking從另一個 ViewModel 呼叫,而BookingListingViewModel此時不可見。BookingListingViewModel永遠不會超出范圍,因為它被傳遞給其他 ViewModel 并且它只是在CurrentViewModelAddBooking 完成后設定。
EDIT2 --> 已洗掉
編輯3
其余代碼
創建BookingViewModel
public ICommand SubmitCreateBookingCommand { get; }
public ICommand CancelCreateBookingCommand { get; }
public ICommand SelectDriverCommand { get; }
public ICommand SelectVehicleCommand { get; }
public ICommand SelectTrailerCommand { get; }
public ICommand SelectHaulierCommand { get; }
/// <summary>
///
/// </summary>
/// <param name="navigationStore"></param>
/// <param name="returnViewModel">View model page should return to</param>
public CreateBookingViewModel(NavigationStore navigationStore, ViewModelBase returnViewModel) // returnViewModel is BookingListingViewModel here
{
WindowStart = DateTime.Now;
WindowEnd = DateTime.Now.AddDays(1);
SubmitCreateBookingCommand = new SubmitNewBookingCommand(navigationStore, this, returnViewModel);
SelectDriverCommand = new NavigateCommand(navigationStore, new DriverListingViewModel(navigationStore, this));
SelectVehicleCommand = new NavigateCommand(navigationStore, new VehicleListingViewModel(navigationStore, this));
SelectTrailerCommand = new NavigateCommand(navigationStore, new TrailerListingViewModel(navigationStore, this));
SelectHaulierCommand = new NavigateCommand(navigationStore, new HaulierListingViewModel(navigationStore, this));
CancelCreateBookingCommand = new NavigateCommand(navigationStore, returnViewModel);
}
提交新預訂命令
private readonly NavigationStore _navigationStore;
private readonly CreateBookingViewModel _createBookingViewModel;
private readonly ViewModelBase _returnViewModel;
private BookingRecord _validateBookingRecord;
public SubmitNewBookingCommand(NavigationStore navigationStore, CreateBookingViewModel createBookingViewModel, ViewModelBase returnViewModel)
{
this._navigationStore = navigationStore;
this._createBookingViewModel = createBookingViewModel;
this._returnViewModel = returnViewModel;
createBookingViewModel.PropertyChanged = OnViewModelPropertyChanged;
}
public override void Execute(object parameter)
{
BookingRecord bookingRecord = new BookingRecord()
{
CustomerReference = _createBookingViewModel.CustomerReference,
WindowStart = _createBookingViewModel.WindowStart,
WindowEnd = _createBookingViewModel.WindowEnd,
DriverId = _createBookingViewModel.DriverId,
VehicleId = _createBookingViewModel.VehicleId,
TrailerId = _createBookingViewModel.TrailerId,
HaulierId = _createBookingViewModel.HaulierId,
RequiresValidation = true
};
BookingService.CreateBooking(bookingRecord, out string[] feedback);
BookingViewModel booking = BookingService.GetBooking(b => true, b => new BookingViewModel()
{
CustomerReference = b.CustomerRef,
WindowStart = b.BookingWindowFrom,
WindowEnd = b.BookingWindowTo,
DriverName = b.Driver.Name,
VehicleRegPlate = b.Vehicle.RegPlate,
TrailerName = b.Trailer.Name,
HaulierName = b.Haulier.Name
});
((BookingListingViewModel)_returnViewModel).AddBooking(booking);
_navigationStore.CurrentViewModel = _returnViewModel;
}
我原來的問題的行為仍然沒有得到回答......
uj5u.com熱心網友回復:
這是一個重現您想要做的事情的演示。AMainViewModel保存預訂串列并導航到CreateBookingViewModel以創建新預訂。然后CreateBookingViewModel呼叫MainViewModel'AddBooking方法將新預訂添加到串列中。
主視窗.xaml
<Window
x:Class="ObservableCollectionDemoApp.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:local="clr-namespace:ObservableCollectionDemoApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button
Grid.Row="0"
Command="{Binding CreateBookingCommand}"
Content="Create booking" />
<ListBox Grid.Row="1" ItemsSource="{Binding Bookings}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding BookingId}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
主視窗.xaml.cs
using System.Windows;
namespace ObservableCollectionDemoApp;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
BookingViewModel.cs
public class BookingViewModel
{
public Guid BookingId { get; set; }
}
主視圖模型.cs
public class MainViewModel
{
private readonly NavigationStore _navigationStore;
public ObservableCollection<BookingViewModel> Bookings { get; } = new ObservableCollection<BookingViewModel>();
public ICommand CreateBookingCommand { get; }
public MainViewModel(NavigationStore navigationStore)
{
_navigationStore = navigationStore;
CreateBookingCommand = new NavigateCommand(navigationStore, new CreateBookingViewModel(navigationStore, this));
}
private void LoadBookings()
{
//load data from somewhere (database?)
Bookings.Add(new BookingViewModel { BookingId = Guid.NewGuid() });
Bookings.Add(new BookingViewModel { BookingId = Guid.NewGuid() });
Bookings.Add(new BookingViewModel { BookingId = Guid.NewGuid() });
}
public void AddBooking(BookingViewModel booking)
{
Bookings.Add(booking);
}
}
創建BookingViewModel.cs
public class CreateBookingViewModel
{
private readonly NavigationStore _navigationStore;
private readonly MainViewModel _parentViewModel;
public CreateBookingViewModel(NavigationStore navigationStore, MainViewModel parentViewModel)
{
_navigationStore = navigationStore;
_parentViewModel = parentViewModel;
}
private void Save()
{
//simulate creating a new booking
var newBooking = new BookingViewModel { BookingId = Guid.NewGuid() };
//add the new booking to the parent view model
_parentViewModel.AddBooking(newBooking);
//navigate back to main window
_navigationStore.NavigateBack();
}
}
uj5u.com熱心網友回復:
我的代碼中的問題在于SubmitNewBookingCommand.Execute
以下代碼檢索第一個找到的專案,而不是我添加的專案,這就是我沒有看到它的原因......我的資料庫中填充了數十個垃圾資料,所以我一開始沒有看到它。
BookingViewModel booking = BookingService.GetBooking(b => true, b => new BookingViewModel()
{
CustomerReference = b.CustomerRef,
WindowStart = b.BookingWindowFrom,
WindowEnd = b.BookingWindowTo,
DriverName = b.Driver.Name,
VehicleRegPlate = b.Vehicle.RegPlate,
TrailerName = b.Trailer.Name,
HaulierName = b.Haulier.Name
});
新代碼
Booking newBooking = BookingService.CreateBooking(bookingRecord, out string[] feedback);
BookingViewModel booking = BookingService.GetBooking(b => b.BookingId == newBooking.BookingId, b => new BookingViewModel()
{
CustomerReference = b.CustomerRef,
WindowStart = b.BookingWindowFrom,
WindowEnd = b.BookingWindowTo,
DriverName = b.Driver.Name,
VehicleRegPlate = b.Vehicle.RegPlate,
TrailerName = b.Trailer.Name,
HaulierName = b.Haulier.Name,
Status = b.BookingStatus.Name
});
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/496854.html
上一篇:在WPF中的MaterialDesign按鈕上更改屬性IsIndeterminate
下一篇:串列框拆分為兩列
