Observable Stack <t>无法正常工作

时间:2016-06-08 15:53:27

标签: c# wpf xaml xaml-binding

我从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时,该按钮仍然是不可见的,我做错了什么?

3 个答案:

答案 0 :(得分: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的回答可能是正确的,您必须包含对RaisePropertyChanged的{​​{1}}次来电。我认为CollectionChanged也会这样做,但进一步的研究似乎表明没有。

答案 1 :(得分: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"));
}

答案 2 :(得分:-2)

那是因为基类Stack没有通知&#34; Count&#34;到绑定目标。您可以通过添加:

手动通知
RaisePropertyChanged(new PropertyChangedEventArgs("Count"));

在OnCollectionChanged方法结束时的内部。