Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataTemplate adaptation is wrong in ItemsRepeater #14

Open
YoshihiroIto opened this issue Sep 16, 2022 · 5 comments
Open

DataTemplate adaptation is wrong in ItemsRepeater #14

YoshihiroIto opened this issue Sep 16, 2022 · 5 comments
Labels
bug Something isn't working

Comments

@YoshihiroIto
Copy link

YoshihiroIto commented Sep 16, 2022

Describe the bug

DataTemplate adaptation is wrong in ItemsRepeater.

Reproduction project

https://github.com/YoshihiroIto/AvaloniaDataTemplateProblem

This project works as follows
Numbers below 100 are displayed in red.
Numbers above 100 are displayed in green.
When the Add Items button is clicked, 10 items are added.
When the Remove Items button is clicked, 10 items are removed.

        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
            <ItemsRepeater Items="{Binding Items}">
                <ItemsRepeater.Layout>
                    <UniformGridLayout MinItemWidth="60" Orientation="Vertical" />
                </ItemsRepeater.Layout>

                <ItemsRepeater.ItemTemplate>
                    <views:DataTemplateSelector>
                        <views:DataTemplateSelector.Under100DataTemplate>
                            <DataTemplate DataType="viewModels:DataViewModel">
                                <TextBlock
                                    Width="60"
                                    Foreground="Red"
                                    Text="{Binding Index}" />
                            </DataTemplate>
                        </views:DataTemplateSelector.Under100DataTemplate>

                        <views:DataTemplateSelector.Over100DataTemplate>
                            <DataTemplate DataType="viewModels:DataViewModel">
                                <TextBlock
                                    Width="60"
                                    Foreground="Green"
                                    Text="{Binding Index}" />
                            </DataTemplate>
                        </views:DataTemplateSelector.Over100DataTemplate>
                    </views:DataTemplateSelector>
                </ItemsRepeater.ItemTemplate>
            </ItemsRepeater>
        </ScrollViewer>
    public class DataTemplateSelector : IDataTemplate
    {
        public IDataTemplate? Over100DataTemplate { get; set; }
        public IDataTemplate? Under100DataTemplate { get; set; }

        public IControl? Build(object? param)
        {
            if (param is not DataViewModel vm)
                throw new NotSupportedException();

            return vm.IsOver100
                ? Over100DataTemplate?.Build(param)
                : Under100DataTemplate?.Build(param);
        }

        public bool Match(object? data)
        {
            return data is DataViewModel;
        }
    }
    public class MainViewModel : ViewModelBase
    {
        public ObservableCollection<DataViewModel> Items { get; } = new();

        public ReactiveCommand<Unit, Unit> AddItemsCommand { get; }
        public ReactiveCommand<Unit, Unit> RemoveItemsCommand { get; }

        public MainViewModel()
        {
            for (var i = 0; i != 200; ++i)
                Items.Add(new DataViewModel { Index = Items.Count });

            AddItemsCommand = ReactiveCommand.Create(() =>
                {
                    for (var i = 0; i != 10; ++i)
                        Items.Add(new DataViewModel { Index = Items.Count });
                }
            );

            RemoveItemsCommand = ReactiveCommand.Create(() =>
                {
                    for (var i = 0; i != 10; ++i)
                        Items.RemoveAt(Items.Count - 1);
                }
            );
        }
    }

    public class DataViewModel : ViewModelBase
    {
        public int Index
        {
            set
            {
                this.RaiseAndSetIfChanged(ref index, value);
                this.RaisePropertyChanged(nameof(IsOver100));
                this.RaisePropertyChanged(nameof(IsUnder100));
            }

            get => index;
        }

        public int index;

        public bool IsOver100 => Index > 100;
        public bool IsUnder100 => !IsOver100;
    }

To Reproduce

After adding and deleting items several times, the colors are displayed incorrectly.

Expected behavior

After repeated addition and deletion of items, below 100 are displayed in red, and above 100 are displayed in green.

Screenshots

2022-09-16-21-00-37.mp4

Desktop

OS: Windows 11
Avalonia: 11.0.0-preview1

@YoshihiroIto YoshihiroIto added the bug Something isn't working label Sep 16, 2022
@timunie
Copy link

timunie commented Sep 16, 2022

As a workaround: would a Converter help you instead of two DataTemplates?

@YoshihiroIto
Copy link
Author

YoshihiroIto commented Sep 16, 2022

@timuenie
Thank you for your reply.

The sample I presented is a minimally reproducible code.
In production, the two DataTemplates are different in structure form each other.

For example. Here's another one I made up artificially

        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
            <ItemsRepeater Items="{Binding Items}">
                <ItemsRepeater.Layout>
                    <UniformGridLayout MinItemWidth="60" MinItemHeight="30" Orientation="Vertical" />
                </ItemsRepeater.Layout>

                <ItemsRepeater.ItemTemplate>
                    <views:DataTemplateSelector>
                        <views:DataTemplateSelector.Under100DataTemplate>
                            <DataTemplate DataType="viewModels:DataViewModel">
                                <StackPanel Width="60" Orientation="Horizontal">
                                    <Rectangle
                                        Width="16"
                                        Height="16"
                                        Fill="Red" />
                                    <TextBlock Foreground="Red" Text="{Binding Index}" />
                                </StackPanel>
                            </DataTemplate>
                        </views:DataTemplateSelector.Under100DataTemplate>

                        <views:DataTemplateSelector.Over100DataTemplate>
                            <DataTemplate DataType="viewModels:DataViewModel">
                                <Button
                                    Content="{Binding Index}"
                                    Foreground="Green" />
                            </DataTemplate>
                        </views:DataTemplateSelector.Over100DataTemplate>
                    </views:DataTemplateSelector>
                </ItemsRepeater.ItemTemplate>
            </ItemsRepeater>
        </ScrollViewer>
2022-09-17-08-44-20.mp4

Does your workaround still work in this situation?

@timunie
Copy link

timunie commented Sep 17, 2022

I also have a workaround for this situation.

Just to be clear: I didn't say here you have a workaround, so this issue doesn't need to be fixed. But at the moment there are lots of efforts going on to prepare 11.0, so I don't know when this issue gets addressed. If you know a solution, PRs are welcome 🤗


My other workaround only works if you have two different DataTemplates: place both different controls into one DataTemplate and bind their IsVisible to the bool property you have.

And I have a third option: Use Avalonia.Behaviors

Happy coding

@timunie
Copy link

timunie commented Sep 17, 2022

Related? #6

@YoshihiroIto
Copy link
Author

@timuenie
Thank you for your reply.

I was able to isolate whether this problem was on the Avalonia side or my implementation.

Thanks for the workaround suggestion.
I have confirmed that the problem is only reproduced with ItemsRepeater. I will work on using ItemsControl.

ItemsControl does not work with virtualization, but the rest of the operation is as desired. I will consider the ItemsRepeater issue after I have more knowledge of Avalonia myself. Or I will implement a panel that virtualization works.

Avalonia.Behaviors was my first attempt at using Avalonia. I myself am an experienced WPF user and tried to handle this with DataTriggerBehavior, but had the same problem.

Thank you again for your help.

@maxkatz6 maxkatz6 transferred this issue from AvaloniaUI/Avalonia Mar 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants