嘗試在 DataGrid 中使用 ComboBox 時,我收到可怕的“雙向系結需要路徑或 XPath”錯誤。是的,我已經看過幾個現有的答案,但似乎沒有一個與我的例子的風格相匹配。對于冗長的代碼,我很抱歉,但我想對我的示例進行徹底的介紹。
SQL Server 資料模型:
-- list of dropdown values lives in here, specifically the CarrierName
create table Carrier
(
CarrierId int identity(1,1) primary key,
CarrierName nvarchar(500) not null,
CarrierType nvarchar(500) not null
);
-- this is what my datagrid will be looking at
create table Contract
(
ContractId int identity(1,1) primary key,
CarrierId int foreign key references Carrier(CarrierId)
-- other attributes removed for example
);
通過 EF Core 中的 Scaffold-DbContext 命令生成的模型:
public partial class Carrier
{
public Carrier()
{
Contracts = new HashSet<Contract>();
}
public int CarrierId { get; set; }
public string CarrierName { get; set; }
public string CarrierType { get; set; }
public virtual ICollection<Contract> Contracts { get; set; }
}
public partial class Contract
{
public Contract() { }
public int ContractId { get; set; }
public int CarrierId { get; set; }
public virtual Carrier Carrier { get; set; }
}
主視圖模型.cs
public class MainViewModel : ViewModelBase
{
public IContractViewModel ContractViewModel { get; set; }
public MainViewModel(IContractViewModel contractViewModel)
{
ContractViewModel = contractViewModel;
}
public async Task LoadAsync()
{
await ContractViewModel.LoadAsync();
}
}
合同視圖模型.cs
public class ContractViewModel : ViewModelBase, IContractViewModel
{
private readonly IRepository _repository;
private CoreContract _selectedContract;
public ObservableCollection<Contract> Contracts { get; set; }
public ObservableCollection<Carrier> Carriers { get; set; }
public Contract SelectedContract
{
get { return _selectedContract; }
set { _selectedContract = value; }
}
public ContractViewModel(IRepository repository)
{
Contracts = new ObservableCollection<Contract>();
Carriers = new ObservableCollection<Carrier>();
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
}
public async Task LoadAsync()
{
Contracts.Clear();
foreach (var contract in await _repository.GetAllContractsAsync())
{
Contracts.Add(contract);
}
Carriers.Clear();
foreach(var carrier in await _repository.GetAllCarriersAsync())
{
Carriers.Add(carrier);
}
}
}
主視窗.cs
public partial class MainWindow : Window
{
private readonly MainViewModel _viewModel;
public MainWindow(MainViewModel mainViewModel)
{
InitializeComponent();
this.Loaded = async (s, e) => await _viewModel.LoadAsync();
_viewModel = mainViewModel;
DataContext = _viewModel;
}
}
主視窗.xaml
<Window xmlns:Views="clr-namespace:COREContracts.Views"
x:Class="COREContracts.Views.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:COREContracts"
mc:Ignorable="d">
<Views:ContractsView DataContext="{Binding ContractViewModel}"/>
</Window>
ContractsView.xaml
因為承運人串列不在合同串列中,所以我使用這個答案來正確鏈接:
<UserControl x:Class="COREContracts.Views.ContractsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Name="root">
<DataGrid Name="Contracts"
ItemsSource="{Binding Contracts}"
SelectedItem="{Binding SelectedContract}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Contract Id" Binding="{Binding Path=ContractId}"/>
<DataGridTemplateColumn Header="Carrier Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Carrier.CarrierName}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Carriers, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
SelectedItem="{Binding Path=SelectedContract.CarrierName}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=CarrierName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</UserControl>
當我將下拉值更新為另一個值然后單擊資料行時,會出現“雙向系結需要路徑或 XPath”例外。
我在這里做錯了什么?
uj5u.com熱心網友回復:
問題在于您的 ComboBox 的 SelectedItems 系結:
SelectedItem="{Binding Path=SelectedContract.CarrierName}">
DataContext 已設定為 SelectedContract,因此無需在此處指定。并且您想系結到 Carrier 物件本身,而不是 CarrierName 屬性:
SelectedItem="{Binding Path=Carrier}">
作為旁注,請記住,像這樣直接系結到您的資料層并不總是最好的主意。您上面的代碼將在您更改 Carrier 屬性時對其進行修改,但它不會將這些更改傳播到您的 Carrier 實體中的 Contracts 串列,因此您的 ORM 很有可能在序列化時忽略任何更改到您的資料庫。一般來說,您的資料層應該與視圖模型中的更高層進行鏡像,該層負責處理這些內容并且更適合視圖。這是一個實作問題,我將留給您解決,因為它在很大程度上取決于您的架構。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/478202.html
上一篇:如何從C#更改XAML字形?
