На самом деле в теме все сказано.
<CollectionViewSource x:Key="MyData"
Source="{Binding}" Filter="{ SomethingMagicInXaml? }" />
Дело не в том, что у меня не может быть кода. Это просто грызет меня.
На самом деле в теме все сказано.
<CollectionViewSource x:Key="MyData"
Source="{Binding}" Filter="{ SomethingMagicInXaml? }" />
Дело не в том, что у меня не может быть кода. Это просто грызет меня.
Вы можете делать в XAML практически все, что угодно, если «достаточно постараться», вплоть до написания на нем целых программ.
Вы никогда не обойдете код позади (ну, если вы используете библиотеки, вам не нужно их писать, но приложение, конечно, полагается на них), вот пример того, что вы можете сделать в этом конкретном случае:
<CollectionViewSource x:Key="Filtered" Source="{Binding DpData}"
xmlns:me="clr-namespace:Test.MarkupExtensions">
<CollectionViewSource.Filter>
<me:Filter>
<me:PropertyFilter PropertyName="Name" Value="Skeet" />
</me:Filter>
</CollectionViewSource.Filter>
</CollectionViewSource>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Markup;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Windows;
using System.Text.RegularExpressions;
namespace Test.MarkupExtensions
{
[ContentProperty("Filters")]
class FilterExtension : MarkupExtension
{
private readonly Collection<IFilter> _filters = new Collection<IFilter>();
public ICollection<IFilter> Filters { get { return _filters; } }
public override object ProvideValue(IServiceProvider serviceProvider)
{
return new FilterEventHandler((s, e) =>
{
foreach (var filter in Filters)
{
var res = filter.Filter(e.Item);
if (!res)
{
e.Accepted = false;
return;
}
}
e.Accepted = true;
});
}
}
public interface IFilter
{
bool Filter(object item);
}
// Sketchy Example Filter
public class PropertyFilter : DependencyObject, IFilter
{
public static readonly DependencyProperty PropertyNameProperty =
DependencyProperty.Register("PropertyName", typeof(string), typeof(PropertyFilter), new UIPropertyMetadata(null));
public string PropertyName
{
get { return (string)GetValue(PropertyNameProperty); }
set { SetValue(PropertyNameProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PropertyFilter), new UIPropertyMetadata(null));
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty RegexPatternProperty =
DependencyProperty.Register("RegexPattern", typeof(string), typeof(PropertyFilter), new UIPropertyMetadata(null));
public string RegexPattern
{
get { return (string)GetValue(RegexPatternProperty); }
set { SetValue(RegexPatternProperty, value); }
}
public bool Filter(object item)
{
var type = item.GetType();
var itemValue = type.GetProperty(PropertyName).GetValue(item, null);
if (RegexPattern == null)
{
return (object.Equals(itemValue, Value));
}
else
{
if (itemValue is string == false)
{
throw new Exception("Cannot match non-string with regex.");
}
else
{
return Regex.Match((string)itemValue, RegexPattern).Success;
}
}
}
}
}
Расширения разметки — ваш друг, если вы хотите что-то сделать в XAML.
(Возможно, вы захотите указать имя расширения по буквам, например me:FilterExtension
, так как проверка на лету в Visual Studio может жаловаться без причины, она все равно компилируется и запускается, конечно, но предупреждения могут раздражать.
Также не ожидайте, что CollectionViewSource.Filter
появится в IntelliSense, он не ожидает, что вы установите этот обработчик с помощью XML-элементной нотации)
ContentProperty
?
- person H.B.; 26.11.2014
me:Filter
не найден. Подтвердите это.........
- person Vishal; 26.11.2014
TraceLevel
, что обычно не требуется. Что ж, вам также нужно понять, что означают различные ошибки и каковы общие причины.
- person H.B.; 26.11.2014
На самом деле вам даже не нужен доступ к экземпляру CollectionViewSource
, вы можете фильтровать исходную коллекцию прямо в ViewModel:
ICollectionView view = CollectionViewSource.GetDefaultView(collection);
view.Filter = predicate;
(обратите внимание, что ICollectionView.Filter
— это не событие, подобное CollectionViewSource.Filter
, это свойство типа Predicate<object>
)
ViewModel
, предоставляющий представление с представлением, звучит как Controller
.
- person XAMlMAX; 21.07.2014
WPF автоматически создает CollectionView
— или один из его производных типов, таких как ListCollectionView
или BindingListCollectionView
, — всякий раз, когда вы привязываете любые исходные данные, производные от IEnumerable
, к свойству ItemsControl.ItemsSource
. Какой тип CollectionView
вы получите, зависит от возможностей, обнаруженных во время выполнения в предоставленном вами источнике данных.
Иногда, даже если вы попытаетесь явно связать свой собственный тип, производный от CollectionView
, с ItemsSource
, механизм привязки данных WPF может обернуть его (используя внутренний тип CollectionViewProxy
).
Автоматически предоставляемый экземпляр CollectionView
создается и поддерживается системой на основе для каждой коллекции (примечание: не для каждого em> управление пользовательским интерфейсом или для каждого привязанного целевого). Другими словами, для каждой коллекции s̲o̲u̲r̲c̲e̲e̲, к которой вы привязаны, будет ровно одно глобально совместно используемое представление по умолчанию, и этот уникальный экземпляр CollectionView
можно получить (или создать по запросу) в любое время, передав тот же исходный экземпляр IEnumerable
снова возвращается к статическому методу CollectionViewSource.GetDefaultView()
.
CollectionView
— это прокладка, способная отслеживать состояние сортировки и/или фильтрации без фактического изменения источника. Следовательно, если на одни и те же исходные данные ссылаются несколько разных Binding
использований, каждое из которых использует разные CollectionView
, они не будут мешать друг другу. Представление по умолчанию предназначено для оптимизации очень распространенных и гораздо более простых ситуаций, когда фильтрация и сортировка не требуются или не ожидаются.
Короче говоря, каждый ItemsControl
со свойством ItemsSource
, привязанным к данным, всегда будет иметь возможности сортировки и фильтрации, любезно предоставленные некоторым преобладающим CollectionView
. Вы можете легко выполнять фильтрацию/сортировку для любого заданного IEnumerable
, захватывая и манипулируя CollectionView
по умолчанию из свойства ItemsControl.Items
, но обратите внимание, что все цели с привязкой к данным в пользовательском интерфейсе, которые в конечном итоге используют это представление — либо потому, что вы явно привязались к CollectionViewSource.GetDefaultView()
, или из-за того, что ваш источник вообще не был CollectionView
— все они будут использовать одни и те же эффекты сортировки/фильтрации.
Что не часто упоминается в этой теме, так это то, что в дополнение к привязке исходной коллекции к свойству
ItemsSource
объектаItemsControl
(в качестве цели привязки) , вы также можете одновременно получить доступ к действующей коллекции примененных результатов фильтрации/сортировки, представленной как производный отCollectionView
экземплярSystem.Windows.Controls.ItemCollection
-- путем привязки от свойствоItems
элемента управления (как источник привязки).
Это позволяет использовать множество упрощенных сценариев XAML:
Если для вашего приложения достаточно единой глобальной возможности фильтрации/сортировки для данного источника IEnumerable
, просто привяжите его напрямую к ItemsSource
. По-прежнему используя только XAML, вы можете фильтровать/сортировать элементы, обрабатывая свойство Items
того же элемента управления как ItemCollection
с привязкой источник. Он имеет много полезных связываемых свойств для управления фильтром/сортировкой. Как уже отмечалось, фильтрация/сортировка будет использоваться всеми элементами пользовательского интерфейса, которые таким образом привязаны к одному и тому же источнику IEnumerable
. --или--
Создайте и примените один или несколько отдельных (не стандартных) экземпляров CollectionView
самостоятельно. Это позволяет каждой цели с привязкой к данным иметь независимые настройки фильтрации/сортировки. Это также можно сделать в XAML и/или создать собственные классы, производные от (List)CollectionView
. Этот тип подхода хорошо описан в другом месте, но здесь я хотел бы отметить, что во многих случаях XAML можно упростить, используя тот же метод привязки данных к свойству ItemsControl.Items
(в качестве источника привязки), чтобы получить доступ к действующему CollectionView
.
Вывод.
С помощью XAML можно выполнить привязку данных к коллекции, представляющей эффективные результаты любой текущей CollectionView
фильтрации. /sorting в WPF ItemsControl
, рассматривая его свойство Items
как источник привязки только для чтения. Это будет System.Windows.Controls.ItemCollection
, который предоставляет привязываемые/изменяемые свойства для управления активным фильтром и критериями сортировки.
[edit] — дополнительные мысли:
Обратите внимание, что в простом случае привязки вашего IEnumerable
напрямую к ItemsSource
ItemCollection
, к которому можно привязать ItemsControl.Items
, будет оболочкой исходной коллекции CollectionViewSource.GetDefaultView()
. Как обсуждалось выше, в случае использования XAML не составляет труда привязаться к этой оболочке пользовательского интерфейса (через ItemsControl.Items
), в отличие от привязки к базовому представлению, которое она обертывает (через CollectionViewSource.GetDefaultView
), поскольку Первый подход избавляет вас от (в XAML, неудобной) проблемы, связанной с необходимостью явного упоминания каких-либо CollectionView
вообще.
Но кроме того, поскольку ItemCollection
оборачивает значение по умолчанию CollectionView
, мне кажется, что даже в code-behind (где выбор менее очевиден ), возможно, также более практично привязываться к представлению, распространяемому пользовательским интерфейсом, поскольку такое представление лучше всего соответствует де-факто возможностям среды выполнения как источника данных, и его пользовательского интерфейса. контрольная цель.