组合框未在 Avalonia 应用程序中填充

Combo Box not being populated in Avalonia Application

提问人:Harlan 提问时间:11/17/2023 更新时间:11/20/2023 访问量:71

问:

我在未填充的窗体上有一个组合框,即使当我单步执行代码时,我也可以看到值已分配给属性。我在这里错过了什么:

.axaml

<UserControl
    xmlns="https://github.com/avaloniaui"
    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"
    xmlns:vm="clr-namespace:TAStagingApp.ViewModels.Implementations.Terminal;assembly=TAStagingApp.ViewModels"
    xmlns:terminal="clr-namespace:TAStagingApp.Views.Terminal;assembly=TAStagingApp"
    mc:Ignorable="d"
    d:DesignWidth="800"
    d:DesignHeight="450"
    x:DataType="vm:TerminalConfigureViewModel"
    x:Class="TAStagingApp.Views.Terminal.TerminalConfigureView"
    Background="{StaticResource TABackgroundColor}">

    <UserControl.DataContext>
        <vm:TerminalConfigureViewModel />
    </UserControl.DataContext>

    <UserControl.Styles>
        <StyleInclude  Source="/Styles/ConfigureViews/Configure.ComboBoxes.axaml" />
        <StyleInclude  Source="/Styles/ConfigureViews/Configure.LabelStyles.axaml" />
        <StyleInclude  Source="/Styles/ConfigureViews/Configure.StackPanels.axaml" />
    </UserControl.Styles>

    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceInclude Source="/Styles/ConfigureViews/Configure.Buttons.axaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <Grid
        ColumnDefinitions="*, Auto, Auto, *"
        RowDefinitions="*, Auto, Auto, Auto, Auto, *"
        Classes="StagingGrid">

        <!-- Instructions Row -->
        <Label
            Classes="ConfigureH1"
            Grid.Row="1"
            Grid.Column="1"
            Grid.ColumnSpan="2">
            PLEASE ENTER THE FOLLOWING INFORMATION:
        </Label>

        <!-- Site ID Row -->
        <StackPanel
            Grid.Row="2"
            Grid.Column="1"
            Classes="ServerConfigureStackPanel">
            <Label
                Classes="ConfigureH2">
                SITE ID:
            </Label>
            <ComboBox
                Classes="Configure"
                Width="296"
                Margin="10 5 5 10"
                ItemsSource="{Binding SiteIds}"
                SelectedItem="{Binding SiteId, Mode=TwoWay}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <ComboBoxItem>
                            <ComboBoxItem.Content>
                                <Binding Path="SiteId" />
                            </ComboBoxItem.Content>
                        </ComboBoxItem>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </StackPanel>

        <!-- Device -->
        <StackPanel
            Grid.Row="3"
            Grid.Column="1"
            Classes="ServerConfigureStackPanel">
            <Label
                Classes="ConfigureH2">
                DEVICE:
            </Label>
            <ComboBox
                Classes="Configure"
                Width="296"
                Margin="10 5 5 10"
                ItemsSource="{Binding Terminals}"
                SelectedItem="{Binding Terminal}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <ComboBoxItem>
                            <ComboBoxItem.Content>
                                <Binding Path="DeviceName" />
                            </ComboBoxItem.Content>
                        </ComboBoxItem>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </StackPanel>

        <!-- Configure Button -->
        <Button
            Grid.Column="1"
            Grid.Row="4"
            Grid.ColumnSpan="2"
            Command="{Binding Configure}"
            Theme="{DynamicResource ConfigureButton}">
            CONFIGURE
        </Button>

    </Grid>

</UserControl>

C#

namespace TAStagingApp.ViewModels.Implementations.Terminal;
public class TerminalConfigureViewModel : ViewModelBase, IConfigureViewModel
{
    private readonly ObservableCollection<SiteIdModel>? _siteIds;
    private readonly ObservableCollection<TerminalModel>? _terminals;

    private readonly IMediator? _mediator;

    private SiteIdModel? _siteId;
    private TerminalModel? _terminal;

    public TerminalConfigureViewModel(IMediator mediator)
    {
        _mediator = mediator;

        _siteIds = [];
        _terminals = [];
    }

    public TerminalConfigureViewModel()
    {
    }

    public IEnumerable<SiteIdModel>? SiteIds => _siteIds;

    public IEnumerable<TerminalModel>? Terminals => _terminals;

    public SiteIdModel? SiteId
    {
        get => _siteId;
        set
        {
            _siteId = value;
            this.RaiseAndSetIfChanged(ref _siteId, value);
            this.RaisePropertyChanged(nameof(Terminals));
            if (_siteId == value)
            {
                _terminals!.Clear();
                GetNewTerminalList();
            }
        }
    }

    [Reactive]
    public TerminalModel? Terminal { get; set; }

    public async void Activate()
    {
        _siteIds!.AddRange(await GetSiteIdListAsync());

        _siteId = SiteId = _siteIds![0];

        _terminal = Terminal = _terminals![0];
    }

    public void Configure()
    {
        throw new NotImplementedException();
    }

    private async void GetNewTerminalList()
    {
        var query = new ListDevicesBySiteIdQuery(_siteId!.SiteId!);
        var queryResult = await _mediator!.Send(query);

        var terminals = new List<TerminalModel>();

        foreach (var result in queryResult.Value)
        {
            terminals.Add(new TerminalModel(
                result.Site!.SiteNumber,
                result.TerminalName));
        }

        _terminals!.AddRange(terminals);
        _terminal = Terminal = _terminals![0];
    }

    private async Task<List<SiteIdModel>> GetSiteIdListAsync()
    {
        var query = new ListSitesQuery();
        var queryResult = await _mediator!.Send(query);

        var siteIds = new List<SiteIdModel>();

        foreach (var result in queryResult.Value)
        {
            siteIds.Add(new SiteIdModel(result.SiteNumber));
        }

        return [.. siteIds.OrderBy(x => x.SiteId)];
    }
}

如果我单步执行视图模型,我可以看到所有属性都已正确填充。但 UI 中不显示任何内容。

谢谢

C# Avaloniaui avalonia

评论


答:

0赞 Tarazed 11/20/2023 #1

您正在向 ObservableCollection 添加内容,但仅限于支持字段。

private readonly ObservableCollection<SiteIdModel>? _siteIds;

但是,可访问属性是 IEnumerable。IEnumerable 可以是 ObservableCollection,但它也可以是一个简单的数组和其他几个东西。视图只能访问 IEnumerable 中定义的成员。

public IEnumerable<SiteIdModel>? SiteIds => _siteIds;

将属性更改为 ObservableCollection,以便在填充列表时通知视图并更新 ItemsSource。

public ObservableCollection<SiteIdModel>? SiteIds => _siteIds;

评论

0赞 Harlan 11/21/2023
我试过了,得到了同样的结果。在 UI 中,“站点 ID”组合框为空,但在代码中,但字段和属性已完全填充。是什么原因导致的?_siteIdsSiteIds
0赞 Tarazed 11/21/2023
在这种情况下,您将不得不尝试制作一个最小的可重现示例。
0赞 Harlan 11/21/2023
我创建了一个测试应用程序,它按照我期望的方式工作,但我仍然无法弄清楚整个应用程序中出了什么问题。https://github.com/hmsiegel/TestAvalonia