【问题标题】:WPF Binding SelectedItem to a property of another objectWPF 将 SelectedItem 绑定到另一个对象的属性
【发布时间】:2021-09-13 23:53:12
【问题描述】:

我想做的是查找一个“类别”以根据 CurrentItem.CategoryId 将 SelectedItem 绑定到与 Category.Id 匹配的位置。

<ListBox ItemsSource="{Binding Categories}" SelectedItem="{Binding CurrentItem.CategoryId, Mode=TwoWay>

我想过使用 IValueConverter,但我不确定如何将 Category.Id 作为 ConverterParameter 传递。或者,如果这甚至是正确的方法。我不得不想象这是一个常见的用例,但我什至不知道用谷歌搜索什么。欢迎提出任何建议!

编辑:好的,那么更多详细信息以及完整代码。事务有一个名为“CategoryId”的属性,它与 Category 类型上的“Id”属性相匹配。我的最终目标是让列表框中的 selectedItem 成为 DataGrid 中当前 SelectedTransaction 所指的任何类别。

应该是双向绑定,ListView应该初始化为Transaction.CategoryId指向的Category,如果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));
        }
    }

【问题讨论】:

  • 如果您显示背后的代码会有所帮助。什么是 CurrentItem?它是一个类别吗?您希望它在 SelectedItem 发生变化时发生变化,还是只需要根据 SelectedItem 更改对象的 .CategoryId 属性?

标签: wpf binding selecteditem ivalueconverter


【解决方案1】:

这应该可行:

<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 属性移动到另一个类中并调用它,例如主视图模型:

DataContext = new MainViewModel();

【讨论】:

  • 谢谢谢谢谢谢!!!昨天我花了几个小时在谷歌搜索绑定和 valueconverters 等周围胡思乱想。只是发现有一个专门用于此目的的烘焙属性哈!我猜你只是不知道你不知道什么。再次感谢!
猜你喜欢
  • 1970-01-01
  • 2020-06-22
  • 2015-09-29
  • 2011-05-26
  • 1970-01-01
  • 2014-12-08
  • 2013-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多