0

我已经从Stackoverflow 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; }
        }
    }

现在我正在尝试使用以下 Converter 类将按钮的可见性绑定到 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 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 时,该按钮仍然不可见,我做错了什么?

4

3 回答 3

1

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

您应该改为绑定到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;
}

并且您希望堆栈通知实现中Count的更改ObservableStack

protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    this.RaiseCollectionChanged(e);
    RaisePropertyChanged(new PropertyChangedEventArgs("Count"));
}
于 2016-06-08T16:11:31.920 回答
1

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 也会这样做,但进一步的研究似乎表明不会。

于 2016-06-08T16:10:02.230 回答
-2

这是因为基类 Stack 没有将“Count”通知给绑定目标。您可以通过添加手动通知:

RaisePropertyChanged(new PropertyChangedEventArgs("Count"));

在 OnCollectionChanged 方法的末尾。

于 2016-06-08T16:07:55.490 回答