好的,我有一个ListBox绑定到ViewModel的属性。 它已经填充了像这样的Caliburn.Micro.BindableCollection
public BindableCollection<QueueTask> QueueTasks
{
get
{
return this._queueProcessor.Queue;
}
}
队列任务有一些这样的属性:
public class QueueTask : PropertyChangedBase
{
private StatusCode _status;
private int _completedPercent;
public StatusCode Status
{
get => _status;
set
{
_status = value;
this.NotifyOfPropertyChange(() => Status);
}
}
public int CompletedPercent
{
get { return _completedPercent; }
set
{
_completedPercent = value;
this.NotifyOfPropertyChange(() => CompletedPercent);
}
}
}
现在您可以看到他的一个属性是StatusCode枚举
public enum StatusCode
{
Waiting = 1,
Processing,
Finished,
Error
}
现在真正的问题是...... 我如何(在视图中)过滤ListBox以仅显示StatusCode中列表的一部分,每个StatusCode使用4个ToggleButtons。因此,如果我按下(或激活)完成按钮,则只在ListBox中显示符合该条件的那些按钮。如果他们都活跃,请向所有人展示。如果没有标记,则不要显示任何内容。
我知道可以使用ICollectionView进行处理。如果它可以在xaml中更好,虽然它可以在View后面的代码中。我的想法是让几个ICollectionView绑定到另一个。作为一个链和每个切换按钮将激活或停用每个过滤器(虽然我仍然需要看到如何做到这一点,即使是一个切换按钮)。我不知道这是否是最好的方法,所以欢迎任何帮助。
对不起我的英语我只会说西班牙语......
答案 0 :(得分:1)
立即提供指向source的链接。
中可以看到它的外观对于过滤器值,我创建了-A1
模型。
这有必要找出我们的属性何时发生变化。
FilterValue
在public class FilterValue
{
private bool _value;
public bool Value
{
get { return _value; }
set
{
_value = value;
ValueChanged?.Invoke();
}
}
public event Action ValueChanged;
}
类中,我添加了QueueTask
属性,以明确列表中的任务内容。
TaskName
然后我创建了一个包含所有元素public class QueueTask : INotifyPropertyChanged
{
private StatusCode _status;
private int _completedPercent;
private string _taskName;
public StatusCode Status
{
get { return _status; }
set
{
_status = value;
OnPropertyChanged(nameof(Status));
}
}
public int CompletedPercent
{
get { return _completedPercent; }
set
{
_completedPercent = value;
OnPropertyChanged(nameof(CompletedPercent));
}
}
public string TaskName
{
get { return _taskName; }
set
{
_taskName = value;
OnPropertyChanged(nameof(Status));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
的列表和一个_allQueueTasks
的视图列表。
用于测试的集合我填写方法QueueTasks
。
我还创建了FillTempData ()
字典,其中包含所有可能的Filters
值。它填入StatusCode
方法。
FillFilters ()
嗯,最后一步是视觉部分的布局。
我使用public class MainViewModel : INotifyPropertyChanged
{
private List<QueueTask> _allQueueTasks;
private List<QueueTask> _queueTasks;
public Dictionary<StatusCode, FilterValue> Filters { get; set; }
public List<QueueTask> QueueTasks
{
get { return _queueTasks; }
set { _queueTasks = value; OnPropertyChanged(nameof(QueueTasks)); }
}
public MainViewModel()
{
FillTempData();
FillFilters();
}
private void FillFilters()
{
Filters = new Dictionary<StatusCode, FilterValue>();
foreach (StatusCode code in Enum.GetValues(typeof(StatusCode)))
{
var newFilter = new FilterValue();
newFilter.ValueChanged += FilterOnValueChanged;
Filters.Add(code, newFilter);
}
}
private void FilterOnValueChanged()
{
var filtredItems = _allQueueTasks.Where(task => Filters[task.Status].Value);
QueueTasks = new List<QueueTask>(filtredItems);
}
private void FillTempData()
{
_allQueueTasks = new List<QueueTask>()
{
new QueueTask() { Status = StatusCode.Waiting, TaskName = "WaitingTask1"},
new QueueTask() { Status = StatusCode.Waiting, TaskName = "WaitingTask2"},
new QueueTask() { Status = StatusCode.Processing, TaskName = "ProcessingTask1"},
new QueueTask() { Status = StatusCode.Processing, TaskName = "ProcessingTask2"},
new QueueTask() { Status = StatusCode.Finished, TaskName = "FinishedTask1"},
new QueueTask() { Status = StatusCode.Finished, TaskName = "FinishedTask2"},
new QueueTask() { Status = StatusCode.Error, TaskName = "ErrorTask1"},
new QueueTask() { Status = StatusCode.Error, TaskName = "ErrorTask2"},
};
QueueTasks = new List<QueueTask>();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
来显示ItemsControl
。
为了显示列表本身,我使用了ToggleButton
。
ListBox
答案 1 :(得分:0)
首先感谢Sean Sexton的这篇文章 https://wpf.2000things.com/2014/01/14/986-filtering-a-listbox-using-a-collectionviewsource/
现在使用CollectionViewSource的解决方案很简单(或多或少)。它在视图中用一些代码实现。
首先创建(CollectionViewSource绑定到完整队列):
<Window.Resources>
<CollectionViewSource Source="{Binding QueueTasks, Mode=OneWay}" x:Key="FilteredQueueTasks" IsLiveFilteringRequested="True">
<CollectionViewSource.LiveFilteringProperties>
<clr:String>Status</clr:String>
</CollectionViewSource.LiveFilteringProperties>
</CollectionViewSource>
</Window.Resources>
然后将ListBox绑定到此CollectionViewSource(简化)。然后它只显示已由CollectionViewSource
过滤的任务<ListBox Grid.Row="2" ItemsSource="{Binding Source={StaticResource FilteredQueueTasks}}" />
视图背后的代码看起来像这样(很大)
public partial class QueueView : Window, INotifyPropertyChanged
{
public QueueView()
{
InitializeComponent();
}
private void QueueTasks_Filter(object sender, FilterEventArgs e)
{
StatusCode status = ((QueueTask) e.Item).Status;
switch (status)
{
case StatusCode.Waiting:
e.Accepted = showWaiting;
break;
case StatusCode.Processing:
e.Accepted = showProcessing;
break;
case StatusCode.Finished:
e.Accepted = showFinished;
break;
case StatusCode.Error:
e.Accepted = showWithErrors;
break;
case StatusCode.Warning:
e.Accepted = showWithWarnings;
break;
default:
e.Accepted = false;
break;
}
}
private bool showWaiting = true;
public bool ShowWaiting
{
get => showWaiting;
set
{
showWaiting = value;
OnPropertyChanged(nameof(ShowWaiting));
((CollectionViewSource)this.Resources["FilteredQueueTasks"]).View.Refresh();
}
}
private bool showProcessing = true;
public bool ShowProcessing
{
get => showProcessing;
set
{
showProcessing = value;
OnPropertyChanged(nameof(ShowProcessing));
((CollectionViewSource)this.Resources["FilteredQueueTasks"]).View.Refresh();
}
}
private bool showFinished;
public bool ShowFinished
{
get => showFinished;
set
{
showFinished = value;
OnPropertyChanged(nameof(ShowFinished));
((CollectionViewSource)this.Resources["FilteredQueueTasks"]).View.Refresh();
}
}
private bool showWithErrors = true;
public bool ShowWithErrors
{
get => showWithErrors;
set
{
showWithErrors = value;
OnPropertyChanged(nameof(ShowWithErrors));
((CollectionViewSource)this.Resources["FilteredQueueTasks"]).View.Refresh();
}
}
private bool showWithWarnings = true;
public bool ShowWithWarnigs
{
get => showWithWarnings;
set
{
showWithWarnings = value;
OnPropertyChanged(nameof(ShowWithWarnigs));
((CollectionViewSource)this.Resources["FilteredQueueTasks"]).View.Refresh();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void Window_Initialized(object sender, EventArgs e)
{
((CollectionViewSource)this.Resources["FilteredQueueTasks"]).Filter += QueueTasks_Filter;
}
}
然后每个ToggleButton都像这样附加到它:
<StackPanel Grid.Row="1" HorizontalAlignment="Right" Height="22" VerticalAlignment="Bottom" Orientation="Horizontal" Margin="-1,0,5,5">
<ToggleButton IsChecked="{Binding ShowWithErrors, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:QueueView}}}">
<Image Source="Images/Error.png" Margin="1" />
</ToggleButton>
<ToggleButton IsChecked="{Binding ShowWithWarnigs, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:QueueView}}}">
<Image Source="Images/Warning.png" Margin="1" />
</ToggleButton>
<ToggleButton IsChecked="{Binding ShowFinished, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:QueueView}}}">
<Image Source="Images/Complete.png" Margin="1" />
</ToggleButton>
<ToggleButton IsChecked="{Binding ShowProcessing, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:QueueView}}}">
<Image Source="Images/Working.png" Margin="1"/>
</ToggleButton>
<ToggleButton IsChecked="{Binding ShowWaiting, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:QueueView}}}">
<Image Source="Images/Movies.png" Margin="1" />
</ToggleButton>
</StackPanel>
当任何ToggleButtons更改其状态以及队列中的任何项目更新其状态时,它会更新过滤器。要使LiveFilter工作,属性必须实现INotifyPropertyChanged,以便它可以通知视图进行更改。