从静态资源绑定到UIElement的属性

时间:2015-12-13 17:12:30

标签: c# wpf xaml mvvm

我为Behavior构建了一个过滤CollectionViewSource,它通常可以正常使用,并按照以下方式使用:

<CollectionViewSource Source="{Binding ListOfStuff}"  x:Key="FilteredListOfStuff">
    <i:Interaction.Behaviors>
        <behaviors:FilterBehavior>
            <behaviors:PropertyFilter Property="SomePropName">
                <behaviors:TextFilter FilterText="filter text"/>
            </behaviors:PropertyFilter>
        </behaviors:FilterBehavior>
    </i:Interaction.Behaviors>
</CollectionViewSource>

问题在于,正如我现在所知,我无法将过滤器属性绑定到UIElements,因为CollectionViewSource是一个静态资源。

我想要的,现在不能做到的是:

<behaviors:TextFilter FilterText="{Binding ElementName=TheSearchTextBox, Path=Text}"/>

有解决方法吗?我的过滤行为是基于使用CollectionViewSource.Filter事件,有没有一个好的,干净的方式来过滤没有&#39; CollectionViewSource&#39;?也就是说,直接向ItemsControl(DataGrid,ListBox等)添加过滤器行为?

我可以通过将TheSearchTextBox.TextFilterText绑定到同一个ViewModel属性来解决这个问题,但是这种类型会破坏MVVM,因为过滤是纯粹的&#34; View&#34;行动...

修改 添加过滤器行为代码:

    [ContentPropertyAttribute("Filters")]
    public class FilterBehavior : Behavior<CollectionViewSource>
    {

        private List<IFilter> _filters;
        public List<IFilter> Filters
        {
            get
            {
                return _filters ??
                            (_filters = new List<IFilter>());
            }
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Filter += CollectionViewSource_Filter;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Filter -= CollectionViewSource_Filter;
        }

        void CollectionViewSource_Filter(object sender, FilterEventArgs e)
        {
            if (Filters != null)
            {
                e.Accepted = Filters.All((f) => !f.IsEnabled || f.Filter(e.Item));
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

我们需要在FilterText类的behaviors:TextFilter属性中提供用户提供的过滤字符串。

创建一个简单的类FilterPropertyElement:

    public class FilterPropertyElement : FrameworkElement
    {
        public override string ToString()
        {
            return Tag.ToString();
        }
    }    

声明资源

<Window.Resources>
         <local:FilterPropertyElement x:Key="FilterPropertyKey" Tag="some filter key value"/>
</Window.Resources>

更改TextFilter定义以使用资源。 :

<behaviors:TextFilter FilterText="{Binding Path=Tag, Source={StaticResource FilterPropertyKey}}"/>

将绑定应用于TextBox,从哪里获取过滤条件

<TextBox Text="{Binding Path=Tag, Source={StaticResource FilterPropertyKey}, UpdateSourceTrigger=LostFocus}" />

答案 1 :(得分:0)

在AnjumSKhan的回答的启发下,我最终做的是将过滤器添加到rood Resources集合并让TextBox绑定到它:

<UserControl.Resources>
    <b:TextFilter x:Key="SearchTextFilter" />
    <CollectionViewSource Source="{Binding ListOfStuff}"  x:Key="FilteredListOfStuff">
        <i:Interaction.Behaviors>
            <b:FilterBehavior>
                <b:PropertyFilter Property="SomePropName">
                    <StaticResource ResourceKey="SearchTextFilter"/>
                </b:PropertyFilter>
            </b:FilterBehavior>
        </i:Interaction.Behaviors>
    </CollectionViewSource>
</UserControl.Resources>
.
.
.
<TextBox Text="{Binding Path=FilterText, Source={StaticResource SearchTextFilter}, Mode=OneWayToSource}"/>

这仍然不像我想的那么干净,但它是我能想到的最好的,如果有人有更好的解决方案,请告诉我。