Привязка стека (который можно переключить) к ListBox - PullRequest
0 голосов
/ 26 мая 2018

У меня есть список объектов (Man), каждый из которых содержит Stack состояний.У меня есть окно отладки, которое показывает выбранный Man стек в ListBox.И у меня есть TabControl, который я использую для выбора Man для отладки.

Чтобы иметь возможность выбрать правильную привязку, я создал свойство, которое возвращает StateStack человека по выбранному индексу TabControl.

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

DebugIndex связан со свойством TabControl 'SelectedIndex.Таким образом, чтобы DebugIndex обновить StateStack, чтобы показать, я использовал OnPropertyChanged:

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

Проблема в том, что когда TabControl 'SelectedIndex меняется, Stackстранно беспорядочно!Ошибка в том, что он неупорядочен только в представлении, а не в данных.

Я думаю, что это происходит из-за того, что я меняю ссылку на привязку, это другой стек, но я незнаете, как это решить ...

Кстати, это работает, когда я добавляю все объекты Man и инициализирую их StateStack в начале.Но как только я позже добавляю Man (и инициализирую его StateStack), например, когда я нажимаю кнопку, он больше не работает ...

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 Ответ

0 голосов
/ 26 мая 2018

Я смоделировал ваш сценарий, и наблюдение состоит в том, что существует проблема с методом Push для того, как элемент NotifyCollectionChangedEventArgs изменяется, распространяется на источник.Текущий код уведомляет, что элементы изменяются из конечного индекса (но для стека элементы добавляются сверху)).Если вы обновите индекс начала уведомления до 0 как NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, 0), то связанный источник отобразит элемент в соответствующем порядке в представлении.Вы можете прочитать о NotifyCollectionChangedEventArgs здесь .

public new void Push(State item) {
    base.Push(item);

    OnCollectionChanged(
        new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, 0));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...