Observable Stack<T> 无法处理推送

Observable Stack<T> is not working on push

我从 Whosebug answer 复制了 ObservableStack。

public class ObservableStack<T> : Stack<T>, INotifyCollectionChanged, INotifyPropertyChanged
    {
        public ObservableStack()
        {
        }

        public ObservableStack(IEnumerable<T> collection)
        {
            foreach (var item in collection)
                base.Push(item);
        }

        public ObservableStack(List<T> list)
        {
            foreach (var item in list)
                base.Push(item);
        }


        public new virtual void Clear()
        {
            base.Clear();
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        public new virtual T Pop()
        {
            var item = base.Pop();
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
            return item;
        }

        public new virtual void Push(T item)
        {
            base.Push(item);
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
        }


        public virtual event NotifyCollectionChangedEventHandler CollectionChanged;


        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            this.RaiseCollectionChanged(e);
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            this.RaisePropertyChanged(e);
        }


        protected virtual event PropertyChangedEventHandler PropertyChanged;


        private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (this.CollectionChanged != null)
                this.CollectionChanged(this, e);
        }

        private void RaisePropertyChanged(PropertyChangedEventArgs e)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, e);
        }


        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add { this.PropertyChanged += value; }
            remove { this.PropertyChanged -= value; }
        }
    }

现在我正尝试使用以下转换器 class:

将按钮的可见性绑定到 Stack.Count
public class StackToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            var collection = (Stack<int>)value;
            return collection.Count > 0  ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

我在后面的代码中将堆栈定义为 public 属性

public ObservableStack<int> myStack;

public MainPage()
{
            myStack = new ObservableStack<int>();
            this.InitializeComponent(); 
            myButton.DataContext = myStack;
}

和XAML如下:

 <Page.Resources>
        <Converters:StackToVisibilityConverter x:Key="StackToVisibilityConverter"/>
    </Page.Resources>


<Button x:Name="myButton" Content="Test Button" Visibility="{Binding Converter={StaticResource StackToVisibilityConverter}}"/>

现在,当我使用另一个按钮点击事件推送一个 int 时,该按钮仍然不可见,我做错了什么?

那是因为基础 class 堆栈没有通知 "Count" 绑定目标。您可以通过添加手动通知:

RaisePropertyChanged(new PropertyChangedEventArgs("Count"));

在 OnCollectionChanged 方法的末尾。

ObservableStack 在其内容更改时进行通告,但您没有通告堆栈本身已更改。由于您的绑定是针对堆栈本身的,因此您需要对其进行宣传。

不幸的是,我不完全确定您如何通告 DataContext 对象已被修改;我只使用 DataContext 对象的属性完成了它。在这种情况下,由于您实际上只使用 Count 属性,您可以将转换器更改为

public class StackToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var count = (int)value;
        return count > 0  ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

然后更新您的绑定以绑定到 Count 而不是 ObservableStack

<Button x:Name="myButton" Content="Test Button" Visibility="{Binding Path=Count, Converter={StaticResource StackToVisibilityConverter}}"/>

ObservableStack应该引发必要的事件以使其工作

filhit 的回答很可能是正确的,您必须包含 RaisePropertyChangedCount 的调用。我认为 CollectionChanged 也会这样做,但进一步的研究似乎表明不会。

堆栈本身不会更改为另一个堆栈,因此在弹出或推送时不会重新评估绑定。

您应该改为绑定到 Count 属性,并更改转换器以将计数转换为可见性。

<Button x:Name="myButton" Content="Test Button" Visibility="{Binding Count, Converter={StaticResource GreaterThanEqualIntToVisibilityConverter}}"/>

转换器:

public object Convert(object value, Type targetType, object parameter, string language)
{
    var count = (int)value;
    return count > 0 ? Visibility.Visible : Visibility.Collapsed;
}

并且您希望堆栈通知 CountObservableStack 实现中发生了更改。

protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    this.RaiseCollectionChanged(e);
    RaisePropertyChanged(new PropertyChangedEventArgs("Count"));
}