【问题标题】:Observable Stack<T> is not working on pushObservable Stack<T> 不能在 push 上工作
【发布时间】:2016-10-09 00:10:57
【问题描述】:

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

【问题讨论】:

  • 我找不到在添加或删除项目时(或发生其他任何事情时)为 "Count" 引发 PropertyChanged 的代码。我想知道 Stack 上是否有任何东西会调用你的 OnPropertyChanged;当你在那里设置断点时,你有没有碰到它? new 的东西也是有问题的。我会刷新这个烂摊子并编写我自己的可观察堆栈,可能来自 ObservableCollection。要么这样,要么我只为 ObservableCollection 编写 Push 和 Pop 扩展方法,然后出去喝杯啤酒。

标签: c# wpf xaml xaml-binding


【解决方案1】:

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

RaisePropertyChanged(new PropertyChangedEventArgs("Count"));

在 OnCollectionChanged 方法的末尾。

【讨论】:

  • Count 仅在转换器内部引用。由于绑定不在Count 上,绑定逻辑不会关心 Count 的变化
【解决方案2】:

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 调用包含在Count 中。我认为 CollectionChanged 也会这样做,但进一步的研究似乎表明不会。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 非常感谢
    猜你喜欢
    • 2019-08-24
    • 1970-01-01
    • 2020-03-09
    • 1970-01-01
    • 2018-12-21
    • 2016-03-31
    • 1970-01-01
    • 2016-11-05
    • 1970-01-01
    相关资源
    最近更新 更多