2

Below is my DataGrid with some attached properties that are associated with the popup controls further down. The ComboBox is populated by an enum.

    <DataGrid Name="GenericDataGrid" 
              helpers:SearchBehaviours.SearchValue="{Binding ElementName=FindTextbox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
              helpers:SearchBehaviours.IsFindPopupOpen="{Binding ElementName=PopupFind, Path=IsOpen, UpdateSourceTrigger=PropertyChanged}"
              helpers:SearchBehaviours.SearchableItems="{Binding ElementName=ComboSearchableItems, Path=SelectedValue, UpdateSourceTrigger=PropertyChanged}" >
    </DataGrid>

    <Popup x:Name="PopupFind">
        <TextBox x:Name="FindTextbox" />
        <ComboBox x:Name="ComboSearchableItems" 
            ItemsSource="{Binding Source={helpers:Enumeration {x:Type helpers:SearchItems}}}"
            DisplayMemberPath="Description"
            SelectedValue="{x:Static helpers:SearchItems.AllItems}"
            SelectedValuePath="Value" />
    </Popup>

Here is the class that handles the behaviors:

class SearchBehaviours
{
    // Using a DependencyProperty as the backing store for IsTextMatch.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsTextMatchProperty =
        DependencyProperty.RegisterAttached("IsTextMatch", typeof(bool), typeof(SearchBehaviours), new UIPropertyMetadata(false));

    public static bool GetIsTextMatch(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsTextMatchProperty);
    }

    public static void SetIsTextMatch(DependencyObject obj, bool value)
    {
        obj.SetValue(IsTextMatchProperty, value);
    }

    public static readonly DependencyProperty SearchValueProperty =
        DependencyProperty.RegisterAttached("SearchValue", typeof(string), typeof(SearchBehaviours), 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 IsFindPopupOpenProperty =
        DependencyProperty.RegisterAttached("IsFindPopupOpen", typeof(bool), typeof(SearchBehaviours),
        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));

    public static bool GetIsFindPopupOpen(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFindPopupOpenProperty);
    }

    public static void SetIsFindPopupOpen(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFindPopupOpenProperty, value);
    }


    public static readonly DependencyProperty SearchableItemsProperty =
        DependencyProperty.RegisterAttached("SearchableItems", typeof(SearchItems), typeof(SearchBehaviours), new PropertyMetadata(SearchItems.AllItems));

    public static SearchItems GetSearchableItems(DependencyObject obj)
    {
        return (SearchItems)obj.GetValue(SearchableItemsProperty);
    }

    public static void SetSearchableItems(DependencyObject obj, SearchItems value)
    {
        obj.SetValue(SearchableItemsProperty, value);
    }
}

The issue is in the following IMultiValueConverter

<Style TargetType="{x:Type DataGridCell}" x:Key="textCellStyle" >
    <Setter Property="helpers:SearchBehaviours.IsTextMatch">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource SearchValueConverter}" FallbackValue="False">
                <Binding Path="Content.Text" RelativeSource="{RelativeSource Self}" />
                <Binding Path="(helpers:SearchBehaviours.SearchValue)" RelativeSource="{RelativeSource Self}" />
                <Binding Path="(helpers:SearchBehaviours.IsFindPopupOpen)" RelativeSource="{RelativeSource Self}"/>
                <Binding Path="(helpers:SearchBehaviours.SearchableItems)" RelativeSource="{RelativeSource Self}"/>
                <Binding />
                <Binding RelativeSource="{x:Static RelativeSource.Self}"/>
            </MultiBinding>
        </Setter.Value>
    </Setter>

    <Style.Triggers>
        <Trigger Property="helpers:SearchBehaviours.IsTextMatch" Value="True">
            <Setter Property="Background" Value="DarkOrange" />
            <Setter Property="Foreground" Value="White"/>
        </Trigger>
    </Style.Triggers>
</Style>

It triggers the IMultiValueConverter up when the popup is open and closed.
It triggers when the textbox text is changed.
However if the SelectedValue changes in the ComboBox it does not trigger.

Below is the converter it is pretty simple at present outputing when triggered.

public class SearchValueConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Console.WriteLine("Triggered");
        return false;
    }

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

[EDIT]

public enum SearchItems
{
    [Description("All Items")]
    AllItems,
    [Description("Selected Items")]
    SelectedItems
}

[END EDIT]

Can someone what the issue is?

Hank
  • 2,456
  • 3
  • 35
  • 83
  • I don't see definition `IsTextMatch` property in `SearchBehaviours` class. I suppose is bool property but your `SearchValueConverter` doesn't return any value in `Convert` method. It should return bool value. Trigger is never raised for this reason. – user2250152 Jan 10 '15 at 12:27
  • Hi @user2250152, I have added IsTextMatch property, your were spot on just a bool property. Added return value also, that was a typo should have been there. Added the enum as well, by default the combobox is set to AllItems, when I select SelectedItems I expect the Converter to trigger however this does not occur. – Hank Jan 11 '15 at 00:48
  • You could try putting a breakpoint on the `SetSearchableItems` method to check whether the attached property setter gets fired when the combo box selection changes. This would at least tell you whether the binding is working. – Steven Rands Jan 14 '15 at 09:38

2 Answers2

2

Change DataGridCell Style code as below :

<Style TargetType="{x:Type DataGridCell}">
        <Setter Property="local:SearchBehaviours.IsTextMatch">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource SearchValueConverter}" FallbackValue="False">
                    <Binding Path="Content.Text" RelativeSource="{RelativeSource Self}" />
                    <Binding Path="(local:SearchBehaviours.SearchValue)" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}" />
                    <Binding Path="(local:SearchBehaviours.IsFindPopupOpen)" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}"/>
                    <Binding Path="(local:SearchBehaviours.SearchableItems)" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}"/>
                    <Binding />
                    <Binding RelativeSource="{x:Static RelativeSource.Self}"/>
                </MultiBinding>
            </Setter.Value>
        </Setter>

        <Style.Triggers>
            <Trigger Property="local:SearchBehaviours.IsTextMatch" Value="True">
                <Setter Property="Background" Value="DarkOrange" />
                <Setter Property="Foreground" Value="White"/>
            </Trigger>
        </Style.Triggers>
    </Style>

You were passing all attached properties of DataGridCell to MultiBinding Converter which was not assigned.In order to solve this issue, you have to pass DataGrid's attached properties to MultiBindingConverter.

UPDATE :

You can also use ComboBox like this :

<ComboBox x:Name="ComboSearchableItems"/>

& Assign ItemSource by code behind to it like this :

ComboSearchableItems.ItemsSource = Enum.GetValues(typeof(SearchItems));

If you want to bind only using XAML then refer this link

Community
  • 1
  • 1
Amol Bavannavar
  • 2,062
  • 2
  • 15
  • 36
  • Hi Amol, this works to a certain extent. I have a couple of questions though. Why would first two properties function properly and the third not? The other thing is the DataGrid is virtualized and rows are recycled which means that a cell drops its ancestry and throws an error: System.Windows.Data Warning: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.DataGrid' – Hank Jan 15 '15 at 02:43
  • I meant to say that I would like to keep the recycling as well. – Hank Jan 15 '15 at 02:46
  • Because popup is not in `VisualTree` of your window. It does not have any parent. Popup is itself a Parent of TextBox & ComboBox. – Amol Bavannavar Jan 15 '15 at 03:42
  • Not sure I completely understand. Is this in regards to the first question? If so (and this is before I tried your resolution) the binding to the SearchValue property on the TextBox is working, and the binding to the IsFindPopupOpen property on the popup is working. So I would have thought that the binding to the SearchableItems property ComboBox which is at the same level as the TextBox should have worked, shouldn't it? – Hank Jan 15 '15 at 03:59
  • This is working perfectly in my machine but I have not virtualized my `DataGrid`... Without Virtualizing it is possible.. – Amol Bavannavar Jan 15 '15 at 04:12
  • Yes I agree, without virtualizing it works, unfortunately I need it to be. What are your thoughts on my last comment? – Hank Jan 15 '15 at 04:20
  • 1
    It is working because you have binded your popups child properties to attached property. In your case Attached Property is a medium you are using for Getting values of popup. It's good in this case... – Amol Bavannavar Jan 15 '15 at 04:23
  • I agree it is a medium to carry over values. Then why is the attached property not working for ComboBox SelectedValue? – Hank Jan 15 '15 at 04:42
-1

Star by using the WPF inspector to examine what you have bound to your control at all.

enter link description here

user853710
  • 1,715
  • 1
  • 13
  • 27