我看到Silverlight 5购买了样式绑定。试图将它应用于ListBox控件,以进行多项选择。我有以下XAML ListBox(代码在WPF应用程序中工作)。
<ListBox ItemsSource="{Binding Values}" SelectionMode="Multiple">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="ListBoxItem">
<TextBlock Text="{Binding DisplayValue}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
当我运行这个时,我得到一个绑定错误,它似乎试图找到“Values”集合类型的IsSelected属性,而不是该集合中的每个单独项目。有没有其他人经历过这个?
更新 添加了要重现的完整代码,您需要滚动列表框以查看输出日志中的错误
public class ValueViewModel : INotifyPropertyChanged
{
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
private string _displayValue;
public string DisplayValue
{
get { return _displayValue; }
set
{
_displayValue = value;
OnPropertyChanged("DisplayValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MainPageViewModel : INotifyPropertyChanged
{
public ObservableCollection<ValueViewModel> _values;
public ObservableCollection<ValueViewModel> Values
{
get { return _values; }
set
{
_values = value;
OnPropertyChanged("Values");
}
}
public MainPageViewModel()
{
Values = new ObservableCollection<ValueViewModel>();
for (var i = 0; i < 50; i++)
Values.Add(new ValueViewModel() { DisplayValue = i.ToString(), IsSelected = (i % 5) == 0 });
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
和XAML:
<Grid x:Name="LayoutRoot" Background="White" >
<Grid.Resources>
<viewmodels:MainPageViewModel x:Key="vmMainPage"/>
</Grid.Resources>
<Grid x:Name="workGrid" DataContext="{Binding Source={StaticResource vmMainPage}}">
<ListBox ItemsSource="{Binding Values}" SelectionMode="Multiple" Height="100">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5" Text="{Binding DisplayValue}"/>
<TextBlock Margin="5" Text="{Binding IsSelected}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
更新2 似乎错误的问题在于,在可滚动的情况下,如果选择项目1,然后向下滚动并选择项目49(在上面的示例中),则第一个选择将丢失。
答案 0 :(得分:1)
我无法重现它。这对我来说可以。这是一个基于您的代码的完整工作示例。我注意到的一个问题是,当呈现ListBoxItem时,它会自动将数据对象上的属性设置为false,而不管它是否为真。因此,如果您加载一个列表并设置其中一些要预先选择的项目,则在呈现ListBoxItem时将取消选择所有项目。防止这种情况的一种方法是使用Dispatcher.BeginInvoke并在那里设置所选项。请参阅下面的代码中的我的评论。
XAML:
<UserControl x:Class="SilverlightApplication12.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid x:Name="LayoutRoot"
Background="White">
<ListBox ItemsSource="{Binding Entities}"
SelectionMode="Multiple">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected"
Value="{Binding Path=IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="ListBoxItem">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Margin="10 0 0 0"
Text="IsSelected:" />
<TextBlock Margin="5 0 0 0"
Text="{Binding IsSelected}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
代码隐藏+实体类:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightApplication12
{
public partial class MainPage : UserControl, INotifyPropertyChanged
{
private ObservableCollection<MyEntity> _Entities;
public ObservableCollection<MyEntity> Entities
{
get { return _Entities; }
set
{
_Entities = value;
OnPropertyChanged("Entities");
}
}
public MainPage()
{
InitializeComponent();
Entities = new ObservableCollection<MyEntity>();
Entities.Add(new MyEntity()
{
Name = "One",
IsSelected = false,
});
Entities.Add(new MyEntity()
{
Name = "Two",
IsSelected = true,
//Even though this is initially true it does not matter.
//When the ListBoxItem is rendered it sets the property to false.
});
Entities.Add(new MyEntity()
{
Name = "Three",
IsSelected = false,
});
LayoutRoot.DataContext = this;
//Enable the following line to set the 2nd item to selected when the page is loaded.
//Dispatcher.BeginInvoke(() => Entities[1].IsSelected = true);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MyEntity : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
private bool _IsSelected;
public bool IsSelected
{
get
{
return _IsSelected;
}
set
{
_IsSelected = value;
OnPropertyChanged("IsSelected");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
答案 1 :(得分:0)
除了<DataTemplate DataType="ListBoxItem">
之外的所有内容对我来说都很好。
如果Values集合是ListBoxItems的集合,则不需要IsSelected绑定。
否则,DataTemplate上的DataType是错误的,应该留空。
答案 2 :(得分:0)
所以我设法找到了一个似乎可以满足我需求的工作场所。一旦Loaded事件被触发,它将设置已加载的值。它包装了MouseDown事件以设置选择状态。它不是一个真正的数据绑定,但可以完成工作,并且仍然保持View清除代码。
<ListBox ItemsSource="{Binding Values}" SelectionMode="Multiple" Height="100">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding DisplayValue, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ei:ChangePropertyAction
TargetObject="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
PropertyName="IsSelected"
Value="{Binding IsSelected}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeftButtonDown">
<ei:ChangePropertyAction
TargetObject="{Binding}"
PropertyName="IsSelected"
Value="{Binding IsSelected, Converter={StaticResource invertBooleanConverter}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>