2015-02-12 7 views
0

Я хочу выделить все ячейки в DataGrid на основе текста поиска в некотором TextBox на мой взгляд. Для этого я следующий статический класс с требуемыми свойствами зависимостей (DP)Ошибка DataBinding с использованием пользовательских зависимостей

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> 

Где мой ULongToDateTimeStringConverter определяется в Style.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, что я получаю

unhanded исключение произошло на потоке пользовательского интерфейса.

Сообщение: Невозможно установить выражение. Он отмечен как «NonShareable» и уже используется. StackTrace: на System.Windows.DependencyObject.SetValueCommon (DependencyProperty Д.П., значение объекта, PropertyMetadata метаданных, булевой coerceWithDeferredReference, булевой coerceWithCurrentValue, OperationType operationType, булева IsInternal) на System.Windows.DependencyObject.SetValue (DependencyProperty дп, значение объекта) ...

Когда я "Копаться Binding Expression" на DataGridTextSearch.SearchValue. Это может быть проблема Snoop, но, хотя это может быть связано с проблемой, которую я испытываю.

Что я здесь делаю неправильно?

Спасибо за ваше время.

ответ

3

Без испытав код связывания путь должен быть

Path="(Helpers:DataGridTextSearch.SearchValue)" 

, потому что это вложенное свойство. См. PropertyPath XAML Syntax на MSDN.

+1

Я тоже не тестировал это, но я думаю, что это может быть правильно. Я помню, что где-то читал, что параунтезис необходим при привязке к прикрепленному свойству – Rachel

+0

@Rachel. Они требуются в путях свойств в привязках, как указано в связанной статье. – Clemens

+0

Существует еще проблема с привязкой к DataGridCell вместо DataGrid, поскольку [bonyjoe указал] (http://stackoverflow.com/a/28476750/302677), хотя я и не совсем уверен, но должен 'Определение DP должно быть 'typeof (DataGrid)' вместо 'typeof (DataGridTextSearch)', чтобы указать, что это прикрепленное свойство для DataGrid'? – Rachel

1

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

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

Это связывание с AttachedProperty на DataGridCell, а не то, что вы хотите связать с которым это вложенное свойство на DataGrid

Это связывание должно правильно привязать к вашей собственности

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

Также вы можете ограничить список объектов, присоединенное свойство может быть таковой t on, в настоящее время каждый объект зависимостей примет ваше прикрепленное свойство, даже если вы намерены использовать его только для 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, который должен привести к вашей текущей привязке ломаться и сообщить об ошибке, а не просто принимать его, но не делать то, что вы ожидаете.

+1

", который должен привести к повреждению текущего сообщения и сообщить об ошибке". Это неверно, поскольку система свойств зависимостей WPF обходит методы оболочки CLR, когда свойство задается привязкой (и другими источниками тоже). См. [Свойства загрузки и зависимости XAML] (https://msdn.microsoft.com/en-us/library/bb613563.aspx) в MSDN. – Clemens

+0

Спасибо за ваш ответ, к сожалению, хотя я был с тобой по поводу изменения XAML, это не сработало. Я все еще смущен, почему это не подчеркивает ячейки. Любые дальнейшие мысли об этом будут оценены. – MoonKnight

+0

@ Clemens у вас есть мысли о провале вышеуказанного подхода? Спасибо за ваше время ... – MoonKnight