WPF 将 SelectedItem 绑定到另一个对象的 属性
WPF Binding SelectedItem to a property of another object
我想做的是查找一个“类别”以根据 CurrentItem.CategoryId 将 SelectedItem 绑定到与 Category.Id.
匹配的位置
<ListBox ItemsSource="{Binding Categories}" SelectedItem="{Binding CurrentItem.CategoryId, Mode=TwoWay>
我想过使用 IValueConverter,但我不确定如何将 Category.Id 作为 ConverterParameter 传递。或者这是否是正确的方法。我不得不想象这是一个常见的用例,但我什至不知道要 google 做什么。欢迎提出任何建议!
编辑:好的,然后是完整代码的更多详细信息。事务有一个名为“CategoryId”的 属性,它与类别类型上的“Id”属性 匹配。我的最终目标是让列表框中的 selectedItem 成为 DataGrid 中当前 SelectedTransaction 所指的任何类别。
它应该是双向绑定,ListView 应该被初始化为 Transaction.CategoryId 指向的类别,如果 ListView 被更新,那么 Transaction.CategoryId 属性 应该被更新。希望这很清楚。
TransactionWindow.xaml
<Window x:Class="Budgeter.TransactionsWindow"
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:Budgeter"
mc:Ignorable="d"
Title="TransactionsWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10px" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="10px" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10px" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="10px" />
</Grid.RowDefinitions>
<DataGrid x:Name="grid" ItemsSource="{Binding Transactions}" AutoGenerateColumns="False" SelectionUnit="FullRow" SelectionMode="Single" Grid.Row="1" Grid.Column="1" Grid.RowSpan="4" SelectedItem="{Binding SelectedTransaction}" SelectionChanged="grid_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Header="Date" Binding="{Binding Date}" Width="*" IsReadOnly="True" />
<DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="*" MinWidth="200" IsReadOnly="True" />
<DataGridTextColumn Header="Amount" Binding="{Binding Amount}" Width="*" IsReadOnly="True" />
<DataGridTextColumn Header="Category" Binding="{Binding Category.Description}" Width="*" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
<DockPanel Grid.Row="1" Grid.Column="2" Grid.RowSpan="3" Margin="5">
<TextBlock Text="Category:" DockPanel.Dock="Top" />
<ListBox ItemsSource="{Binding Categories}" SelectedItem="{Binding ???" DockPanel.Dock="Bottom">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Grid>
</Window>
TransactionWindow.xaml.cs
public partial class TransactionsWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public IList<CategoryViewModel> Categories { get; }
public IList<TransactionViewModel> Transactions { get; }
public TransactionViewModel SelectedTransaction { get; set; }
public TransactionsWindow(IList<CategoryViewModel> categories, IList<TransactionViewModel> transactions)
{
InitializeComponent();
this.Categories = categories;
this.Transactions = transactions;
if (this.Transactions != null && this.Transactions.Count > 0)
{
this.SelectedTransaction = transactions[0];
}
this.DataContext = this;
}
private void grid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.OnPropertyChanged(nameof(SelectedTransaction));
}
protected void OnPropertyChanged(string name = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
这应该有效:
<ListBox ItemsSource="{Binding Categories}"
SelectedValuePath="Id"
SelectedValue="{Binding SelectedTransaction.CategoryId"}>
请注意,SelectedIndex、SelectedItem 和 SelectedValue 默认绑定 TwoWay。
SelectedTransaction 属性 应该触发 PropertyChanged 事件:
private TransactionViewModel selectedTransaction;
public TransactionViewModel SelectedTransaction
{
get { return selectedTransaction; }
set
{
selectedTransaction = value;
OnPropertyChanged(nameof(SelectedTransaction));
}
}
您还应该考虑将所有这些 TransactionsWindow 属性移动到另一个 class 并调用它,例如主视图模型:
DataContext = new MainViewModel();
我想做的是查找一个“类别”以根据 CurrentItem.CategoryId 将 SelectedItem 绑定到与 Category.Id.
匹配的位置<ListBox ItemsSource="{Binding Categories}" SelectedItem="{Binding CurrentItem.CategoryId, Mode=TwoWay>
我想过使用 IValueConverter,但我不确定如何将 Category.Id 作为 ConverterParameter 传递。或者这是否是正确的方法。我不得不想象这是一个常见的用例,但我什至不知道要 google 做什么。欢迎提出任何建议!
编辑:好的,然后是完整代码的更多详细信息。事务有一个名为“CategoryId”的 属性,它与类别类型上的“Id”属性 匹配。我的最终目标是让列表框中的 selectedItem 成为 DataGrid 中当前 SelectedTransaction 所指的任何类别。
它应该是双向绑定,ListView 应该被初始化为 Transaction.CategoryId 指向的类别,如果 ListView 被更新,那么 Transaction.CategoryId 属性 应该被更新。希望这很清楚。
TransactionWindow.xaml
<Window x:Class="Budgeter.TransactionsWindow"
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:Budgeter"
mc:Ignorable="d"
Title="TransactionsWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10px" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="10px" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="10px" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="10px" />
</Grid.RowDefinitions>
<DataGrid x:Name="grid" ItemsSource="{Binding Transactions}" AutoGenerateColumns="False" SelectionUnit="FullRow" SelectionMode="Single" Grid.Row="1" Grid.Column="1" Grid.RowSpan="4" SelectedItem="{Binding SelectedTransaction}" SelectionChanged="grid_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Header="Date" Binding="{Binding Date}" Width="*" IsReadOnly="True" />
<DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="*" MinWidth="200" IsReadOnly="True" />
<DataGridTextColumn Header="Amount" Binding="{Binding Amount}" Width="*" IsReadOnly="True" />
<DataGridTextColumn Header="Category" Binding="{Binding Category.Description}" Width="*" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
<DockPanel Grid.Row="1" Grid.Column="2" Grid.RowSpan="3" Margin="5">
<TextBlock Text="Category:" DockPanel.Dock="Top" />
<ListBox ItemsSource="{Binding Categories}" SelectedItem="{Binding ???" DockPanel.Dock="Bottom">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Grid>
</Window>
TransactionWindow.xaml.cs
public partial class TransactionsWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public IList<CategoryViewModel> Categories { get; }
public IList<TransactionViewModel> Transactions { get; }
public TransactionViewModel SelectedTransaction { get; set; }
public TransactionsWindow(IList<CategoryViewModel> categories, IList<TransactionViewModel> transactions)
{
InitializeComponent();
this.Categories = categories;
this.Transactions = transactions;
if (this.Transactions != null && this.Transactions.Count > 0)
{
this.SelectedTransaction = transactions[0];
}
this.DataContext = this;
}
private void grid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.OnPropertyChanged(nameof(SelectedTransaction));
}
protected void OnPropertyChanged(string name = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
这应该有效:
<ListBox ItemsSource="{Binding Categories}"
SelectedValuePath="Id"
SelectedValue="{Binding SelectedTransaction.CategoryId"}>
请注意,SelectedIndex、SelectedItem 和 SelectedValue 默认绑定 TwoWay。
SelectedTransaction 属性 应该触发 PropertyChanged 事件:
private TransactionViewModel selectedTransaction;
public TransactionViewModel SelectedTransaction
{
get { return selectedTransaction; }
set
{
selectedTransaction = value;
OnPropertyChanged(nameof(SelectedTransaction));
}
}
您还应该考虑将所有这些 TransactionsWindow 属性移动到另一个 class 并调用它,例如主视图模型:
DataContext = new MainViewModel();