WPF中ListView的SelectedItem无法绑定

3
我一直在尝试将两个ListView绑定到ViewModel。两个列表都成功加载了项目。但令我惊讶的是,我遇到了一个小问题。第一个ListView的SelectedItem正确地绑定了,但第二个没有绑定!如下图所示。可能的原因是什么?
XAML:
<Window x:Class="Test.Dialogs.BeamElevationsWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:converters="clr-namespace:Test.Dialogs.Converters"
        Title="Select Beam Elevation" Height="350" Width="460"
        Style="{StaticResource DialogStyle}"
        WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <converters:ElevationValueConverter x:Key="ElevationValueConverter"/>
    </Window.Resources>

    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <GroupBox>
            <Grid Margin="5">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="175"/>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="215"/>
                </Grid.ColumnDefinitions>
                <GroupBox Header="Typs">
                    <ListView ItemsSource="{Binding TypIds}"
                              SelectedItem="{Binding CurrentTypId}">
                        <ListView.View>
                            <GridView AllowsColumnReorder="False"  
                          ColumnHeaderContainerStyle="{StaticResource DialogsGridViewColumnHeaderStyle}" >
                                <GridViewColumn Header="Typ."/>
                            </GridView>
                        </ListView.View>
                    </ListView>
                </GroupBox>

                <GroupBox Grid.Row="0" Grid.Column="2" Header="Elevations">
                    <ListView ItemsSource="{Binding Elevations}"
                              SelectedItem="{Binding CurrentBeamElevation}">
                        <ListView.View>
                            <GridView AllowsColumnReorder="False"  
                          ColumnHeaderContainerStyle="{StaticResource DialogsGridViewColumnHeaderStyle}" >
                                <GridViewColumn Header="Typ." />
                            </GridView>
                        </ListView.View>
                    </ListView>
                </GroupBox>
            </Grid>
        </GroupBox>
        <Grid Grid.Row="1">
            <Button Content="OK"/>
        </Grid>
    </Grid>
</Window>

代码后台:

public partial class BeamElevationsWindow
{
    private BeamElevationsViewModel ViewModel { get; set; }

    public BeamElevationsWindow()
    {
        InitializeComponent();
        ViewModel = new BeamElevationsViewModel();
        DataContext = ViewModel;
    }
}

ViewModel:

namespace Test.Dialogs.ViewModels
{
    public class BeamElevationsViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public BeamElevationsViewModel()
        {
            var frames = Building.Frames
                .GroupBy(f => f.TypId)
                .Select(group => group.First())
                .OrderBy(f => f.TypId)
                .ToList();

            typIds = new List<int>();
            foreach (var frame in frames)
            {
                typIds.Add(frame.TypId);
            }

            TypIds = typIds;
            CurrentTypId = Building.CurrentFrame.TypId;

            GetElevations(CurrentTypId);
            CurrentBeamElevation = Building.CurrentBeamElevation;
        }

        public void GetElevations(int typId)
        {
            var frames = Building.Frames
                .Where(f => f.TypId == typId)
                .OrderByDescending(f => f.Elevation)
                .ToList();

            elevations = new List<Elevation>();
            foreach (var fr in frames)
            {
                foreach (var elevation in Building.Elevations)
                {
                    if (Math.Abs(fr.Elevation - elevation.El) < Arithmetics.Tolerance)
                    {
                        elevations.Add(elevation);
                        break;
                    }
                }
            }

            Elevations = elevations;
        }

        private List<int> typIds;
        public List<int> TypIds
        {
            get { return typIds; }
            private set
            {
                typIds = value;
                RaisePropertyChanged("TypIds");
            }
        }

        private int currentTypId;
        public int CurrentTypId
        {
            get { return currentTypId; }
            private set
            {
                currentTypId = value;
                RaisePropertyChanged("CurrentTypId");
            }
        }

        private List<Elevation> elevations;
        public List<Elevation> Elevations
        {
            get { return elevations; }
            private set
            {
                elevations = value;
                RaisePropertyChanged("Elevations");
            }
        }

        private Elevation currentBeamElevation;
        public Elevation CurrentBeamElevation
        {
            get { return currentBeamElevation; }
            private set
            {
                currentBeamElevation = value;
                RaisePropertyChanged("CurrentBeamElevation");
            }
        }

        private void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

你展示的内容中没有显示出错误。鉴于代码量很大,你能否更具体地说明你期望看到什么,以及你实际看到了什么? - BradleyDotNET
@BradleyDotNET 感谢您的关注,正如您所看到的,左侧的 ListView 的 SelectedItem 已经正确绑定并选择了 [1]。但是右侧的 ListView 的 SelectedItem 没有正确绑定,因此没有选择任何内容! - Vahid
1
好的,谢谢您的澄清。我认为问题在于相等性检查上,您能否告诉我 Building.CurrentElevation 是不是列表中的完全相同的对象?还是它只有相等的属性? - BradleyDotNET
@BradleyDotNET 你是指 Building.CurrentBeamElevation 吗?它的类型是 Elevation,与列表相同。 - Vahid
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - BradleyDotNET
1
哦,我明白你的意思了,恐怕这不是同一个实例。 - Vahid
1个回答

4
绑定实际上运行良好 :)
然而,对于的默认比较器执行引用比较。这意味着当它尝试在列表中查找现有对象时,它不会选择任何一个对象,因为它们不是同一实例(根据您的评论)。
解决方案是重写Object.Equals(并且当您重写它时,还应该重写Object.GetHashCode)。它应该基于对象的某个唯一属性测试相等性,以便您不会得到错误的结果。

非常感谢你,Bradley!你真是太棒了!这完全解决了我的问题。Building.CurrentBeamElevation与列表中的项目不同。我知道这可能是代码异味,但现在我使用 LINQ 做了一个小技巧,从列表中返回所选项目,并将 SelectedItem 绑定到它上面! - Vahid
@Vahid,我会只覆盖Equals方法,这样可能更容易,而且肯定不容易出错。不过很高兴你已经解决了问题! - BradleyDotNET
你指的是 Elevation 类的 Equals 方法吗? - Vahid
@Vahid 是的,那个类覆盖了 (Object.Equals) 方法。 - BradleyDotNET
非常感谢,我会尝试的。 - Vahid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接