SelectedItem 不在 WPF 的 ListView 中绑定
SelectedItem doesn't bind in ListView in WPF
我一直在努力Bind
这两个ListViews
到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>
Code-Behind:
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));
}
}
}
}
绑定实际上工作正常:)
但是,object
的默认比较器会进行 reference 比较。这意味着当它试图在列表中查找现有对象时,它不会选择其中任何一个,因为它们不是同一个实例(根据您的评论)。
解决方案是覆盖 Object.Equals
(当您覆盖它时,您还应该覆盖 Object.GetHashCode
)。它应该根据对象的一些独特 属性 来测试相等性,这样你就不会得到误报。
我一直在努力Bind
这两个ListViews
到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>
Code-Behind:
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));
}
}
}
}
绑定实际上工作正常:)
但是,object
的默认比较器会进行 reference 比较。这意味着当它试图在列表中查找现有对象时,它不会选择其中任何一个,因为它们不是同一个实例(根据您的评论)。
解决方案是覆盖 Object.Equals
(当您覆盖它时,您还应该覆盖 Object.GetHashCode
)。它应该根据对象的一些独特 属性 来测试相等性,这样你就不会得到误报。