使用自定义依赖项属性的DataBinding失败

时间:2015-02-12 11:26:53

标签: c# wpf xaml mvvm snoop

我想根据我视图中某些DataGrid的搜索文本突出显示TextBox中的所有单元格。为此,我有以下带有所需依赖属性(DP)的静态类

public static class DataGridTextSearch
{
    public static readonly DependencyProperty SearchValueProperty = 
        DependencyProperty.RegisterAttached("SearchValue", typeof(string), typeof(DataGridTextSearch),
              new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits));

    public static string GetSearchValue(DependencyObject obj) {
        return (string)obj.GetValue(SearchValueProperty);
    }

    public static void SetSearchValue(DependencyObject obj, string value) {
        obj.SetValue(SearchValueProperty, value);
    }

    public static readonly DependencyProperty HasTextMatchProperty =
         DependencyProperty.RegisterAttached("HasTextMatch", typeof(bool), 
            typeof(DataGridTextSearch), new UIPropertyMetadata(false));

    public static bool GetHasTextMatch(DependencyObject obj) {
        return (bool)obj.GetValue(HasTextMatchProperty);
    }

    public static void SetHasTextMatch(DependencyObject obj, bool value) {
        obj.SetValue(HasTextMatchProperty, value);
    }
}

然后在我的XAML中,我有以下

<UserControl x:Class="GambitFramework.TaurusViewer.Views.TaurusViewerView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:Caliburn="http://www.caliburnproject.org"
             xmlns:Converters="clr-namespace:GambitFramework.TaurusViewer.Converters"
             xmlns:Helpers="clr-namespace:GambitFramework.TaurusViewer.Helpers">
    <UserControl.Resources>
        <ResourceDictionary>    
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="../Resources/Styles.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <Converters:ULongToDateTimeStringConverter x:Key="ULongToDateTimeStringConverter"/>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <TextBox Name="SearchTextBox"
                 Grid.Row="0"
                 Margin="5"
                 Width="250"
                 VerticalContentAlignment="Center"
                 Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <TabControl Grid.Row="1">
            <TabItem Header="Events">
                <DataGrid x:Name="EventsGrid"
                          HorizontalAlignment="Stretch"
                          VerticalAlignment="Stretch"
                          AutoGenerateColumns="False" 
                          CanUserAddRows="False" 
                          CanUserDeleteRows="False"
                          SelectionUnit="FullRow"
                          EnableRowVirtualization="True" 
                          EnableColumnVirtualization="True" 
                          IsSynchronizedWithCurrentItem="True"
                          VirtualizingStackPanel.VirtualizationMode="Standard"
                          Helpers:DataGridTextSearch.HasTextMatch="False" 
                          Helpers:DataGridTextSearch.SearchValue="{Binding ElementName=SearchTextBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
                          GridLinesVisibility="{Binding GridLinesVisibility}" 
                          SelectedItem="{Binding SelectedEvent, Mode=TwoWay}"
                          ItemsSource="{Binding EventsCollection}">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="Event ID" IsReadOnly="True" Binding="{Binding event_id}"/>
                        <DataGridTextColumn Header="Competition" IsReadOnly="True" Binding="{Binding comp}"/>
                        <DataGridTextColumn Header="Home Team" IsReadOnly="True" Binding="{Binding home}"/>
                        <DataGridTextColumn Header="Away Team" IsReadOnly="True" Binding="{Binding away}"/>
                        <DataGridTextColumn Header="Start Time" 
                                            IsReadOnly="True"
                                            Binding="{Binding start_time, Converter={StaticResource ULongToDateTimeStringConverter}}"/>
                    </DataGrid.Columns>
                    <DataGrid.Resources>
                        <Converters:SearchValueConverter x:Key="SearchValueConverter"/>
                        <Style TargetType="{x:Type DataGridCell}">
                            <Setter Property="Helpers:DataGridTextSearch.HasTextMatch">
                                <Setter.Value>
                                    <MultiBinding Converter="{StaticResource SearchValueConverter}">
                                        <Binding RelativeSource="{RelativeSource Self}" Path="Content.Text"/>
                                        <Binding RelativeSource="{RelativeSource Self}" Path="Helpers:DataGridTextSearch.SearchValue"/>
                                    </MultiBinding>
                                </Setter.Value>
                            </Setter>
                            <Style.Triggers>
                                <Trigger Property="Helpers:DataGridTextSearch.HasTextMatch" Value="True">
                                    <Setter Property="Background" Value="Orange"/>
                                    <!--<Setter Property="Background" Value="{DynamicResource HighlightBrush}"/>-->
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </DataGrid.Resources>
                </DataGrid>
            </TabItem>
        </TabControl>
    </Grid>
</UserControl>

我的ULongToDateTimeStringConverterStyle.xaml中定义并正常工作且SearchValueConverter定义为

public class SearchValueConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture) {
        string cellText = values[0] == null ? string.Empty : values[0].ToString();
        string searchText = values[1] as string;
        if (!string.IsNullOrEmpty(searchText) && !string.IsNullOrEmpty(cellText))
            return cellText.ToLower().StartsWith(searchText.ToLower());
        return false;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, 
        object parameter, System.Globalization.CultureInfo culture) {
        return null;
    }
}

问题是,SearchValueConverter转换器似乎只在加载网格时被调用。我用Snoop来检查绑定,所有都是绿色和好的。按键时,Helpers:DataGridTextSearch.SearchValue在使用Snoop检查的元素中发生变化,但转换器代码从未被使用/调用过。我认为这是一个DataContext问题,但我不确定如何找到确切或确实如何解决这个问题。我的DataContext由Caliburn以通常的方式设定。

我在Snoop中注意到我正在

  

用户界面线程上发生了无法处理的异常。

     

消息:无法设置表达式。它被标记为“不可共享”&#39;并且已经被使用过。   堆栈跟踪:      在System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp,Object value,PropertyMetadata metadata,Boolean coerceWithDeferredReference,Boolean coerceWithCurrentValue,OperationType operationType,Boolean isInternal)      在System.Windows.DependencyObject.SetValue(DependencyProperty dp,Object value)      ...

当我&#34; Delve Binding Expression&#34;在DataGridTextSearch.SearchValue。这可能是一个Snoop问题,但我可能与我遇到的问题有关。

我在这里做错了什么?

感谢您的时间。

2 个答案:

答案 0 :(得分:3)

未经测试您的代码,绑定路径应为

Path="(Helpers:DataGridTextSearch.SearchValue)"

因为它是一个附属物。请参阅MSDN上的PropertyPath XAML Syntax

答案 1 :(得分:1)

从我所看到的,看起来你的问题就是这个绑定

<Binding RelativeSource="{RelativeSource Self}" Path="Helpers:DataGridTextSearch.SearchValue"/>

这是绑定到DataGridCell上的AttachedProperty,而不是绑定到DataGrid上附加属性的内容

此绑定应正确绑定到您的属性

<Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" Path="Helpers:DataGridTextSearch.SearchValue"/>

此外,您可以限制可以设置附加属性的对象,当前每个依赖项对象都将接受您的附加属性,即使您只想将其作为DataGrid。

public static string GetSearchValue(DataGrid obj) {
    return (string)obj.GetValue(SearchValueProperty);
}

public static void SetSearchValue(DataGrid obj, string value) {
    obj.SetValue(SearchValueProperty, value);
}

更改这样的属性定义将限制属性的设置和获取仅限于DataGrid,这会导致当前绑定中断并报告错误,而不仅仅是接受它而不是按照预期执行。