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

コンテンツが変更された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 もこれを行うと思っていましたが、さらなる調査ではそうではないことが示されているようです。

于 2016-06-08T16:10:02.230 に答える
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 に答える
-2

これは、基本クラスの Stack がバインディング ターゲットに "Count" を通知しないためです。以下を追加して、手動で通知できます。

RaisePropertyChanged(new PropertyChangedEventArgs("Count"));

OnCollectionChanged メソッドの最後の内部。

于 2016-06-08T16:07:55.490 に答える