2013-03-27 108 views
1

我看到Silverlight 5買了樣式綁定。試圖將其應用於ListBox控件中,以進行多項選擇。我有以下XAML列表框(代碼在WPF應用程序中工作)。Silverlight 5 ListBox IsSelected風格綁定破壞?

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

當我運行此我得到一個綁定錯誤,它似乎試圖找到「價值」集合的類型,而不是從該集合各個項目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

看起來沒問題。嘗試從綁定中刪除「路徑」。但這應該工作。 – Evgeny 2013-03-27 09:48:12

+0

嘗試它有無路徑,相同的行爲:( – 2013-03-27 10:04:17

回答

0

所以我設法找到這似乎對我的需要做的工作一workarround。一旦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> 
0

除此之外的一切<DataTemplate DataType="ListBoxItem">看起來不錯。


如果Values集合是ListBoxItems的集合,則不需要IsSelected綁定。

否則,DataTemplate上的DataType是錯誤的,應該留空。

+0

更新了完整的代碼,刪除了這個,仍然重現 – 2013-03-27 11:41:25

1

我無法複製它。這對我來說可以。這是一個基於你的代碼的完整工作示例。但我注意到的一個問題是,當呈現ListBoxItem時,它會自動將數據對象上的屬性設置爲false,而不管它是否爲真。因此,如果你加載一個列表並設置它的一些項目被預先選中,所有的項目將在ListBoxItems被渲染時被取消選擇。防止這種情況的一種方法是使用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)); 
      } 
     } 
    } 
} 
+0

它可能與你正在描述的內容有關,的確他們將全部設置爲false,只收到錯誤當項目不在初始視圖中並且您必須滾動時,我已使用完整代碼進行更新以重現錯誤。 – 2013-03-27 11:22:03

+0

應用程序代碼實際上是在應用程序內各個位置使用的模板內。我正在尋找更多的MVVM導向的解決方案,不需要編輯視圖:( – 2013-03-27 14:21:56