代码之家  ›  专栏  ›  技术社区  ›  Drarig29

将堆栈(可以切换)绑定到列表框

  •  1
  • Drarig29  · 技术社区  · 6 年前

    我有一张物品清单( Man )每个都包含一个 Stack 美国的。 我有一个调试窗口,显示 挑选出来的 成年男子 一堆 ListBox . 我有一个TabControl,我用它来选择一个人进行调试。

    为了能够选择正确的绑定,我创建了一个返回 StateStack 在选定的索引中 TabControl .

    public object StateStack => Men[DebugIndex].States;
    

    DebugIndex 这是必然的 选项卡控件 是的 SelectedIndex 所有物所以 调试索引 更新 状态堆栈 为了展示,我用 OnPropertyChanged :

    public int DebugIndex {
        get => _debugIndex;
        set {
            _debugIndex = value;
            OnPropertyChanged(nameof(StateStack));
        }
    }
    

    问题是,当 选项卡控件 是的 选择索引 变化 堆栈 奇怪的混乱!问题是,它只是在视图中无序,而不是在数据中。

    我认为这是因为我改变了绑定的引用,这是另一个堆栈,但我不知道如何解决这个问题。。。

    顺便说一句,当我添加所有Man对象并在开始时初始化它们的状态堆栈时,它就起作用了。但是,当我稍后添加一个人(并初始化其状态堆栈)时,例如当我单击一个按钮时,它就不再工作了。。。

    public sealed partial class MainWindow : INotifyPropertyChanged {
    
        private int _debugIndex;
    
        public ObservableCollection<Man> Men { get; } = new ObservableCollection<Man>();
    
        public MainWindow() {
            Men.Add(new Man {Index = 0, States = new StateStack()});
    
            InitializeComponent();
    
            Men[0].States.Push(new State {Name = "Falling1"});
            Men[0].States.Push(new State {Name = "Walking1"});
    
            //this is simplified code. I push states here because in my program it's done during runtime (not during initialization)
        }
    
        public object StateStack => Men[DebugIndex].States;
    
        public int DebugIndex {
            get => _debugIndex;
            set {
                _debugIndex = value;
                OnPropertyChanged(nameof(StateStack));
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged([CallerMemberName] string propertyName = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
        private void ButtonBase_OnClick(object sender, RoutedEventArgs e) {
            Men.Add(new Man {Index = 1, States = new StateStack()});
    
            Men[1].States.Push(new State {Name = "Falling2"});
            Men[1].States.Push(new State {Name = "Walking2"});
            Men[1].States.Push(new State {Name = "Running2"});
        }
    }
    
    public class Man {
        public int Index { get; set; }
        public StateStack States { get; set; }
    }
    
    public class State {
        public string Name { private get; set; }
    
        public override string ToString() {
            return Name;
        }
    }
    
    public sealed class StateStack : Stack<State>, INotifyCollectionChanged {
    
        public new void Push(State item) {
            base.Push(item);
    
            OnCollectionChanged(
                new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, Count - 1));
        }
    
        public event NotifyCollectionChangedEventHandler CollectionChanged;
    
        private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
            CollectionChanged?.Invoke(this, e);
        }
    }
    

    我的视图代码:

    <Window x:Class="ObservableStackBug.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800" DataContext="{Binding RelativeSource={RelativeSource Self}}">
    
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
    
            <Button Content="Add" Margin="5" Padding="8 2" HorizontalAlignment="Left" Click="ButtonBase_OnClick"/>
    
            <ListBox ItemsSource="{Binding StateStack}" Grid.Row="1" />
    
            <TabControl Grid.Row="2" ItemsSource="{Binding Men}" SelectedIndex="{Binding DebugIndex}">
                <TabControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Index}" />
                    </DataTemplate>
                </TabControl.ItemTemplate>
            </TabControl>
        </Grid>
    
    </Window>
    

    我该怎么对我的绑定说,当DebugIndex更改时,StateStack是一个 另一堆 ?

    1 回复  |  直到 6 年前
        1
  •  1
  •   user1672994    6 年前

    我模拟了你的情景,观察到你的行为有问题 Push 方法如何 NotifyCollectionChangedEventArgs 如果项已更改,则会传播到源。当前代码通知从结束索引更改项目(但对于堆栈,项目添加在顶部)。如果将通知开始索引更新为 0 NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, 0) 然后,绑定源将在视图中以适当的顺序显示该项。您可以阅读关于NotifyCollectionChangedEventArgs的信息 here .

    public new void Push(State item) {
        base.Push(item);
    
        OnCollectionChanged(
            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, 0));
    }