我从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时,该按钮仍然是不可见的,我做错了什么?
答案 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方法结束时的内部。