2015-12-30 3 views
2

У меня есть простой ListView с триггером, также я использую mvvm light RelayCommand. Главный вопрос: почему, когда функция ChangeShowingMode(ObservableCollection<Employee> items) срабатывает в консоли, отображается только Firing: 0. Почему он не показывает также Firing: 1, Firing: 5, Firing: 11, Firing: 99. Как это сделать?ListView странное поведение с смешением смешивания

XMLNS: я = "http://schemas.microsoft.com/expression/2010/interactions" XMLNS: е = "http://schemas.microsoft.com/expression/2010/interactivity"

<Grid> 
    <ListView ItemsSource="{Binding Items}"> 
     <ListView.ItemTemplate> 
      <DataTemplate> 
       <Grid> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition/> 
         <ColumnDefinition/> 
        </Grid.ColumnDefinitions> 
        <CheckBox IsChecked="{Binding IsChecked}" VerticalAlignment="Center"> 
         <ei:Interaction.Triggers> 
          <ei:EventTrigger EventName="Checked"> 
           <ei:InvokeCommandAction Command="{Binding DataContext.IsCheckedTrueCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Views:MainWindow}}}" CommandParameter="{Binding .}"/> 
          </ei:EventTrigger> 
         </ei:Interaction.Triggers> 
        </CheckBox> 
        <Label Grid.Column="1" Content="{Binding Name}" VerticalAlignment="Center"/> 
       </Grid> 
      </DataTemplate> 
     </ListView.ItemTemplate> 
    </ListView> 
</Grid> 

код выглядит следующим образом:

namespace WpfApplication 
{ 
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new ListViewModel(); 
    } 
} 
public class Employee : ViewModelBase 
{ 
    private bool isChecked; 
    public bool IsChecked 
    { 
     get 
     { 
      return this.isChecked; 
     } 

     set 
     { 
      this.isChecked = value; 
      this.RaisePropertyChanged("IsChecked"); 
     } 
    } 

    public string Name { get; set; } 
} 
public class ListViewModel : ViewModelBase 
{ 
    private ObservableCollection<Employee> items; 
    public ObservableCollection<Employee> Items 
    { 
     get 
     { 
      return this.items; 
     } 

     set 
     { 
      this.items = value; 
      this.RaisePropertyChanged("Items"); 
     } 
    } 

    public ListViewModel() 
    { 
     Items = new ObservableCollection<Employee>(); 
     LoadAsync(); 
    } 
    public void LoadAsync() 
    { 
     Task t = null; 
     t = Task.Factory.StartNew(new Action(() => 
     { 
      System.Threading.Thread.Sleep(5000); 
      ObservableCollection<Employee> temporaryItems = new ObservableCollection<Employee>(); 
      for (int i = 0; i < 100; i++) 
      { 
       temporaryItems.Add(new Employee { IsChecked = false, Name = i.ToString() }); 
      } 
      Items = temporaryItems; 
     })); 
     t.ContinueWith((key) => { ChangeShowingMode(Items); }); 
    } 
    public void ChangeShowingMode(ObservableCollection<Employee> items) 
    { 
     Items[0].IsChecked = true; 
     Items[1].IsChecked = true; 
     Items[5].IsChecked = true; 
     Items[11].IsChecked = true; 
     Items[99].IsChecked = true; 
    } 

    public RelayCommand<Employee> IsCheckedTrueCommand 
    { 
     get 
     { 
      return new RelayCommand<Employee>((emp) => Command(emp)); 
     } 
    } 

    public void Command(Employee emp) 
    { 
     Console.WriteLine("Firing: {0}", emp.Name); 
    } 
} 

}

+0

Если предположить, что '' IsChecked' поднимает INPC.PropertyChanged' событие, я предполагаю, что это делать с, что вы делаете вы это из 'Задачи'. Вы можете изменить свойство «Employee.IsChecked» на любом из них с помощью события «PropertyChanged», которое должно быть повышено в потоке пользовательского интерфейса (через 'Dispatcher') – dkozl

+0

Вы ошибаетесь, потому что t.ContinueWith ((key) => {ChangeShowingMode (Items);}); Восстанавливает поток пользовательского интерфейса. Я думаю, проблема связана с виртуализацией или чем-то еще такого рода. – A191919

+0

Нет, это не так. Пока вы не укажете подходящий 'TaskScheduler', например' TaskScheduler.FromCurrentSynchronizationContext() ' – dkozl

ответ

1

проверяемого Событие будет раи se только для видимых флажков. Таким образом, команда вызывается только для видимых.

sample UI

К испытанию ваш при условии, например, свойства устанавливаются задачи, а также отражено, как и ожидалось от UI. Но команда вызывается только при ручной проверке флажка, а не на инициализации.

Изменение

t.ContinueWith((key) => { ChangeShowingMode(Items); }); 

в

t.ContinueWith((key) => { Syste.Threading.Thread.Sleep(5000); ChangeShowingMode(Items); }); 

имеет результат, что команда вызывается для видимого Флажки. Если вы открываете флажок, когда отображаются флажки, команда вызывается для флажка 99.

Но это поведение совсем не странно. Я думаю, что это timming-Issue, когда ваша viewmodel связана с Datacontext или нет.

Ответ на ваш вопрос «Как это сделать?» зависит от вашей проблемы с текущим решением.

Чтобы посмотреть изменения недвижимости, вы можете: How to Listen to Property Changes of Items of an ObservableCollection и вызвать команду на изменения.

Но я думаю, что вам это совсем не нужно. Проверенное состояние отражается вашим IsChecked-Property через двустороннюю привязку.

<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" VerticalAlignment="Center"> 

Таким образом, вы можете легко получить их

var checkedItemsList = Items.Where(ele => ele.IsChecked).ToList(); 

И если вы сделаете изменения по коду, вы можете вызвать команду вручную в вашем ViewModel.

Items[0].IsChecked = true; 
if (IsCheckedTrueCommand.CanExecute(Items[0])) 
    IsCheckedTrueCommand.Execute(Items[0]); 

Но я не уверен, что приведу вас сюда. Остается вопрос, что команда должна делать в расширенном сценарии.

Btw, какую версию Framework вы используете?См check box binding not working on .NET 3.5 SP1

И вызвать Comand на веб-интерфейсе, вы можете использовать:

<CheckBox CommandParameter="{Binding}" 
           Command="{Binding DataContext.CheckBoxCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" 
           IsChecked="{Binding IsChecked, Mode=TwoWay}" VerticalAlignment="Center"> 
+0

Заменить в моем коде t.ContinueWith ((key) => {ChangeShowingMode (Items);}); с t.ContinueWith ((ключ) => {Syste.Threading.Thread.Sleep (5000); ChangeShowingMode (Items);}); И я думаю, что это тоже будет интересно. :) – A191919

+0

@ A191919 Я проверил это, см. Мой обновленный ответ. С новым годом! – gReX

Смежные вопросы