【问题标题】:SelectedItem doesn't bind in ListView in WPFSelectedItem 在 WPF 的 ListView 中没有绑定
【发布时间】:2015-01-13 20:51:33
【问题描述】:

我一直在尝试将Bind 两个ListViews 转换为ViewModel。两个列表都正确加载了项目。但令我惊讶的是,我遇到了一个小问题。

第一个ListViewSelectedItem 绑定正确,但第二个没有绑定!如下图所示。可能是什么原因?

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;
    }
}

视图模型:

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 感谢 Bradley 的关注,您可以看到左侧 ListView 的 SelectedItem 已正确绑定并选择了 [1]。但是右边ListView的SelectedItem没有正确绑定,没有选中!
  • 好的,感谢您的澄清。我认为问题在于相等性检查,您能告诉我Building.CurrentElevation 是否与列表中的一个完全相同的对象?还是只是具有相同的属性?
  • @BradleyDotNET 你的意思是Building.CurrentBeamElevation?是Elevation的类型,和list一样。
  • 哦,我明白你的意思了,恐怕不是同一个实例。

标签: c# wpf xaml listview data-binding


【解决方案1】:

绑定实际上工作正常:)

不过,object 的默认比较器会进行 reference 比较。这意味着当它试图在列表中查找现有对象时,它不会选择其中任何一个,因为它们不是同一个实例(根据您的评论)。

解决方案是覆盖Object.Equals(当你覆盖它时,你也应该覆盖Object.GetHashCode)。它应该根据对象的某些独特属性来测试相等性,这样您就不会得到误报。

【讨论】:

  • 非常感谢布拉德利,你一针见血!这完全解决了我的问题。 Building.CurrentBeamElevation 与列表中的项目不同。我知道这可能是代码异味,但现在我做了一些小技巧,使用LINQ 从列表中返回所选项目并将 SelectedItem 绑定到它!
  • @Vahid 我会刚刚完成Equals 覆盖,它可能更容易,而且绝对不易出错。很高兴你让它工作了!
  • 你是说Elevation类的Equals方法?
  • @Vahid 是的,该类的方法覆盖 (Object.Equals)
  • 非常感谢,那我试试。
猜你喜欢
  • 2018-07-07
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2011-10-06
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 2016-11-30
相关资源
最近更新 更多