0

I have a property composed of email addresses of operators currently editing a record:

    public ReactiveList<string> Operators { get; set; }

On the view side, I have a ListView of records, and for each of them an icon shows if the current user is an editing operator.

<FontIcon Glyph="&#xE104;" Visibility="{Binding Operators, 
    Converter={StaticResource IsUserEditingToVisibilityConverter} }" />

My problem is that the Convert() method of IsUserEditingToVisibilityConverter is not triggered when an update occurs in Operators. A TextBlock I set for debugging purpose does update though:

<TextBlock Text="{Binding Operators[0]}" />

Here's the code of IsUserEditingToVisibilityConverter:

// Taken from https://blogs.msdn.microsoft.com/mim/2013/03/11/tips-winrt-converter-parameter-binding/
public class IsUserEditingToVisibilityConverter : DependencyObject, IValueConverter
{
    public UserVm CurrentUser
    {
        get { return (UserVm)GetValue(CurrentUserProperty); }
        set { SetValue(CurrentUserProperty, value); }
    }

    public static readonly DependencyProperty CurrentUserProperty =
        DependencyProperty.Register("CurrentUser",
                                    typeof(UserVm),
                                    typeof(IsUserEditingToVisibilityConverter),
                                    new PropertyMetadata(null));

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (this.CurrentUser == null) return Visibility.Collapsed;
        if (this.CurrentUser.EmailAddress == null) return Visibility.Collapsed;
        var operators = value as IList<string>;
        if (operators != null && operators.Contains(this.CurrentUser.EmailAddress))
        {
            return Visibility.Visible;
        }
        return Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
ericdes
  • 612
  • 1
  • 6
  • 12

1 Answers1

0

The binding to Text will only update here Operators changes - as in if you were to do something like:

Operators = new ReactiveList<string>{"first", "second"};

and Operators was declared as below (which ensures that PropertyChanged is raised):

public ReactiveList<string> Operators
{
    get { return _operators; }
    set { this.RaiseAndSetIfChanged(ref _operators, value); }
}

It will not update if you add items to or remove items from the list.

I think you're probably doing too much in a converter here - this behaviour would be better off in the View Model. You'd have a CurrentUser property, an Operators list, and declare property using ReactiveUI's ObservableAsPropertyHelper that would update when either CurrentUser or Operators changed:

private readonly ObservableAsPropertyHelper<bool> _isUserEditing;

public ReactiveList<string> Operators { get; } = new ReactiveList<string>();

public UserVm CurrentUser
{
    get { return _currentUser; }
    set { this.RaiseAndSetIfChanged(ref _currentUser, value); }
}

public bool IsUserEditing => _isUserEditing.Value;

And in the constructor:

Operators.Changed.Select(_ => Unit.Default)
    .StartWith(Unit.Default)
    .Select(_ => WhenCurrentUserEditing())
    .Switch()
    .ToProperty(this, x => x.IsUserEditing, out _isUserEditing);

With WhenCurrentUserEditing implemented as:

private IObservable<bool> WhenCurrentUserEditing()
{
    return this.WhenAnyValue(x => x.CurrentUser.EmailAddress)
        .Select(Operators.Contains);
}
Charles Mager
  • 25,735
  • 2
  • 35
  • 45
  • I thought that a ReactiveList would trigger an item added / removed... Also I understand your solution would be fine if I had the information on Operators in my sub viewmodel, which is not the case. – ericdes Apr 05 '16 at 07:52