Question

EDIT: HERE IS ANOTHER (SIMPLER) VERSION OF THE QUESTION:

Assume I have an application with a TextBox used to search for Persons (in DB, local storage, etc.). When typing a person the search is done, and the UI should be updated according to the found Person. In my case the UI contains a single TextBlock showing the value of a property Person.ShortName.

For that I need to use a helper class PersonQueryCreator of the following idea:

public class PersonQueryCreator : DependencyObject
{
  #region Static Data Members

  public static DependencyProperty ShortNameToSearchProperty = DependencyProperty.Register("ShortNameToSearch", typeof(string), typeof(PersonQueryCreator), new PropertyMetadata(UpdateQueryObject));
  private static DependencyPropertyKey QueryPropertyKey = DependencyProperty.RegisterReadOnly("Query", typeof(string), typeof(PersonQueryCreator), new PropertyMetadata());
  public static DependencyProperty QueryProperty = QueryPropertyKey.DependencyProperty;

  #endregion

  #region Public Properties

  public string ShortNameToSearch
  {
    get { return (string)GetValue(ShortNameToSearchProperty); }
    set { SetValue(ShortNameToSearchProperty, value); }
  }

  public object Query
  {
    get { return (string)GetValue(QueryProperty); }
  }

  #endregion

  #region Public Methods

  public static IPerson SearchForPerson(object query)
  {
    ...
  }

  #endregion
}

This class have some properties I can set to create the query (in this example I'll use PersonQueryCreator.ShortNameToSearch) and it produces a query object which is returned in the property PersonQueryCreator.Query. This class also provide a static method PersonQueryCreator.SearchForPerson which accepts a query argument and returns a Person object.

So I have to use a Converter to show the right Person's ShortName in the TextBlock. I could bind the short name TextBlock directly to the search TextBox and use a converter to query and return the ShortName property. However, if I'll do that, then the TextBlock will not be updated if the Person.ShortName content is changed (without changing the Person object reference itself).

AND HERE GOES THE ORIGINAL QUESTION

I have a DAL object contains a collection of persons. The DAL object defines a directed tree graph of relationships between the persons and I would like to show a ListBox of the 'child' related persons of a single person.

Since the relationships are defined in the DAL and not within the person object, I need to define an applicative logics which know to use the appropriate DAL methods. Thus I use a converter which is used in the ListBox.ItemsSource Binding as follows (sorry for the code-behind style :) ).

  BindingBase relationsBinding = new MultiBinding()
  {
    Bindings =
    {
      new Binding() { Source = this, Path = new PropertyPath("Person") },
      new Binding() { Source = this, Path = new PropertyPath("DAL") }
    },
    Converter = PersonToRelationsConverter.Instance,
  };
  ListBox relationsList = new ListBox()
  {
    ItemTemplate = relationsBinding 
  };
  relationsList.SetBinding(ListBox.ItemsSourceProperty, relationsBinding);

The converter code is something like:

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
  IPerson person = values[0] as IPerson;
  IDAL<IPerson> dal = values[1] as IDAL<IPerson>;

  IPersonRelations<IPerson> relations = dal.GetPersonRelations(person);
  IEnumerable<IPerson> children = relations.OutRelated;
  return children;
}

Then I can use ItemTemplate to define how each child person is shown.

It may work, but the problem is that IPersonRelations<IPerson> is an INotifyPropertyChanged object which I would like to enjoy its data change notification. In the mentioned way I cannot enjoy it, because it is only a local variable of the ValueConverter and is not returned to WPF mechanisms.

I guess that the ListBox.ItemsSource is only example for a situation in which the IValueConverter must return some specific object which is not INotifyPropertyChanged or DependencyObject (or not the only one I would like the Binding to listen). I would expect some CompositeBinding class which allows "concatenating" ValueConverters so the Binding mechanism will listen to any value in the concatenated "path".

Do I miss some very simple way to do such thing?

Thanks for help.

Était-ce utile?

La solution

The only way I found doing that is to implement a "middle" dependency object which is bound to the middle value.

So I defined a middle object BindingMiddle which stores the query result, and only later bind to the ShortName property of the result, as follows:

<Window.Resources>

  <local:PersonQueryCreator x:Key="QueryCreator" />

  <local:BindingMiddle x:Key="QueriedPersonContainer">
   <local:BindingMiddle.MiddleValue>
    <Binding Source="{StaticResource QueryCreator}" Path="Query">
      <Binding.Converter>
        <infra:PersonSearcherConverter />
      </Binding.Converter>
    </Binding>
   </local:BindingMiddle.MiddleValue>
  </local:BindingMiddle>

</Window.Resources>

...

    <TextBox Text="{Binding Source={StaticResource QueryCreator}, Path=ShortNameToSearch}"/>

    <TextBlock Text="{Binding Source={StaticResource QueriedPersonContainer}, Path=MiddleValue.ShortName}" />

The code of the ValueConverter and the MiddleBinding is trivial:

public class BindingMiddle : DependencyObject
{
  #region Static Data Members

  public static DependencyProperty MiddleValueProperty = DependencyProperty.Register("MiddleValue", typeof(object), typeof(BindingMiddle));

  #endregion

  #region Public Properties

  public object MiddleValue
  {
    get { return GetValue(MiddleValueProperty); }
    set { SetValue(MiddleValueProperty, value); }
  }

  #endregion
}

public class PersonQueryCreator : DependencyObject
{
  #region Static Data Members

  public static DependencyProperty ShortNameToSearchProperty = DependencyProperty.Register("ShortNameToSearch", typeof(string), typeof(PersonQueryCreator), new PropertyMetadata(ShortNameChanged));
  private static DependencyPropertyKey QueryPropertyKey = DependencyProperty.RegisterReadOnly("Query", typeof(string), typeof(PersonQueryCreator), new PropertyMetadata());
  public static DependencyProperty QueryProperty = QueryPropertyKey.DependencyProperty;

  #endregion

  #region Public Properties

  public string ShortNameToSearch
  {
    get { return (string)GetValue(ShortNameToSearchProperty); }
    set { SetValue(ShortNameToSearchProperty, value); }
  }

  public object Query
  {
    get { return (string)GetValue(QueryProperty); }
  }

  #endregion

  #region Public Methods

  public static IPerson SearchForPerson(object query)
  {
    string shortNameToSearch = query as string;
    return new Prayer(shortNameToSearch, shortNameToSearch);
  }

  #endregion

  #region Private Methods

  private static void ShortNameChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
  {
    ((PersonQueryCreator)o).SetValue(PersonQueryCreator.QueryPropertyKey, e.NewValue);
  }

  #endregion
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top