最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Avalonia ListBox throws error when switching back and forth using ContenControl - Stack Overflow

programmeradmin2浏览0评论

I'm using

<ListBox ItemsSource="{Binding MyItems}"  
         Height="500" 
         HorizontalAlignment="Stretch"/>

When I populate MyItems from the view model, everything works as expected. But when I then use

<ContentControl Content="{Binding LeftPanel}"/>

Assign LeftPanel to something else and switch back, I get this error:

System.InvalidOperationException: 'An anchor control must be a visual descendent of the ScrollContentPresenter.'

This only happens when I manually fill the list, not changing it (it's blank at the beginning). But I think that's just because there is no scrolling when the list is empty.

I should also mention, the list info is read async and I use this to populate it:

void FillListBox(string[] files)
{
    Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
    {
        CreateListboxItems(files);
    });
}

private void CreateListboxItems(string[] files)
{
    MyItems.Clear();
    int length = files.Length;
    for (int i = 0; i < length; i++)
    {
        ListBoxItem item = CreateListboxItem(files[i]);
        RenderFrameItems.Add(item);
    }
}

ListBoxItem CreateListboxItem(string filePath)
{
    Avalonia.Media.FontStyle fontStyle = File.Exists(filePath) ? Avalonia.Media.FontStyle.Normal : Avalonia.Media.FontStyle.Italic;

    ListBoxItem response = new ListBoxItem()
    {
        Content = filePath,
        FontStyle = fontStyle,
    };

    return response;
}

I also tried putting the list into its own scroll view, but same result.

EDIT: Using ObservableCollection<string> rather than ObservableCollection<ListBoxItem> works, but I don't get the formatting I want

I'm using

<ListBox ItemsSource="{Binding MyItems}"  
         Height="500" 
         HorizontalAlignment="Stretch"/>

When I populate MyItems from the view model, everything works as expected. But when I then use

<ContentControl Content="{Binding LeftPanel}"/>

Assign LeftPanel to something else and switch back, I get this error:

System.InvalidOperationException: 'An anchor control must be a visual descendent of the ScrollContentPresenter.'

This only happens when I manually fill the list, not changing it (it's blank at the beginning). But I think that's just because there is no scrolling when the list is empty.

I should also mention, the list info is read async and I use this to populate it:

void FillListBox(string[] files)
{
    Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
    {
        CreateListboxItems(files);
    });
}

private void CreateListboxItems(string[] files)
{
    MyItems.Clear();
    int length = files.Length;
    for (int i = 0; i < length; i++)
    {
        ListBoxItem item = CreateListboxItem(files[i]);
        RenderFrameItems.Add(item);
    }
}

ListBoxItem CreateListboxItem(string filePath)
{
    Avalonia.Media.FontStyle fontStyle = File.Exists(filePath) ? Avalonia.Media.FontStyle.Normal : Avalonia.Media.FontStyle.Italic;

    ListBoxItem response = new ListBoxItem()
    {
        Content = filePath,
        FontStyle = fontStyle,
    };

    return response;
}

I also tried putting the list into its own scroll view, but same result.

EDIT: Using ObservableCollection<string> rather than ObservableCollection<ListBoxItem> works, but I don't get the formatting I want

Share Improve this question edited Jan 27 at 10:05 Frederik Steinmetz asked Jan 22 at 14:48 Frederik SteinmetzFrederik Steinmetz 2312 silver badges8 bronze badges 3
  • Provide a Minimal, Reproducible Example ... – Ibram Reda Commented Jan 22 at 17:23
  • As a note, "the list info is read async" is probably a misconception. The CreateListboxItems method runs synchronously in the UI thread. – Clemens Commented Jan 24 at 7:32
  • I did not post enough code, as I thought it might be a know/typical issue and I didn't want to go overboard. The CreateListboxItems is called from a process from which I read the standard output async. – Frederik Steinmetz Commented Jan 27 at 10:23
Add a comment  | 

1 Answer 1

Reset to default 0

I solved it like this:

Instead of using ObservableCollection<ListBoxItem> I created my own class:

public class FileListItem
    {
        public string Filename { get; set; }
        public FontStyle FontStyle { get; set; }
        public FileListItem(string filename, FileStatus status) 
        {
            FontStyle = status == FileStatus.Existing ? FontStyle.Normal : FontStyle.Italic;
            Filename = filename;
        }
    }


In the ViewModel use:

private ObservableCollection<FileListItem> _fileListItems;
public ObservableCollection<FileListItem> FileListItems
    {
        get => _fileListItems;
        set => SetProperty(ref _fileListItems, value);
    }

And then used a DataTemplate to format the ListBoxItems.

<ListBox ItemsSource="{Binding FileListItems}">
        <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Filename}" FontStyle="{Binding FontStyle}"/>
                </DataTemplate>
        </ListBox.ItemTemplate>
</ListBox>

I know the original Post did not include enough information, but here is the gist:
ObservableCollection<ListBoxItem> - which I think is the natural approach - doesn't seem to work. DataTemplateBinding using a custom class does.

The getter, setter seems to be essential, but I haven't tested removing the private var.
Complete description: https://docs.avaloniaui/docs/guides/data-binding/how-to-bind-to-a-collection

发布评论

评论列表(0)

  1. 暂无评论