如何在下拉菜单中加载组合框项目

问题描述 投票:0回答:1

我需要使用带有一些工作表的excel工作簿。要将可用的工作表加载到组合框中,我需要打开工作簿并遍历所有工作表,然后将它们添加到组合框中。这花费了大量时间,用户需要等待。如果用户不想更改预加载的属性,则此时间很短。因此,我只想在需要时填写列表项,但显示预选属性,该属性是在应用启动时从设置文件加载的。

那么有没有办法在下拉菜单中加载项目?或者更好的是,如何绑定下拉菜单中触发的命令来加载项目?

<ComboBox SelectedItem="{Binding Worksheet}" ItemsSource="{Binding WorkSheets}" x:Name="cbWorkSheet" Padding="4">

...哦,我知道如何将命令绑定到按钮,所以我需要组合框的特殊提示,而不是一般的命令:)

UPDATE我解决了触发“加载”的问题,并且列表已填充,但是我需要显示最后一个选定的值(在启动时作为绑定属性工作表加载)

<ComboBox 
    x:Name="cbWorkSheet" 
    SelectedItem="{Binding Worksheet}" 
    ItemsSource="{Binding WorkSheets}" 
    IsEditable="True"
    Padding="4">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="DropDownOpened" SourceObject="{Binding ElementName=cbWorkSheet}">
                <i:InvokeCommandAction Command="{Binding LoadBACnetWsCombobox}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
</ComboBox>

有了该绑定,组合框保持为空,直到我将其下拉:(

wpf command dropdown
1个回答
0
投票

原始答案:不正确,发布日期2020/06/02:

如果您需要在打开下拉菜单之前填充SelectedItem,则可能应该将EventTrigger的EventName从DropDownOpened更改为Loaded

那样,在向用户显示组合框之前,将运行LoadBACnetWsComboBox,希望可以设置您的Worksheet。然后,组合框将显示给用户。

修改后的答案,发布日期2020/06/03:

根据您对我的原始答案的评论,我已经使用我的这份工作副本进行了修改。我选择删除触发器和命令操作(我没有Interaction命名空间),而是采用了ComboBox的IsDropDownOpen属性之外的方式使用MVVM模式。

MainWindow.xaml:

<Window x:Class="ComboBoxDropdownTest.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"
        xmlns:local="clr-namespace:ComboBoxDropdownTest"
        mc:Ignorable="d"
        Title="{Binding Title}" Height="450" Width="800">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:WorksheetViewModel}">
            <Grid>
                <TextBlock Text="{Binding Name,FallbackValue=FixYourBinding}" />
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ComboBox x:Name="cbWorkSheet" 
                  SelectedItem="{Binding Worksheet, Mode=OneWay}"
                  ItemsSource="{Binding Worksheets}" 
                  IsEditable="True"
                  Padding="4"
                  IsDropDownOpen="{Binding IsDropDownOpen}"
                  VerticalAlignment="Center"
                  Margin="5"
                  Width="400"
                  Text="{Binding SelectedAtStartup}"
            >
            <ComboBox.ItemContainerStyle>
                <Style TargetType="ComboBoxItem">
                    <Setter Property="IsSelected" Value="{Binding Selected}"/>
                </Style>
            </ComboBox.ItemContainerStyle>
        </ComboBox>
    </Grid>
</Window>

MainWindow.xaml.cs:

using System.Windows;

namespace ComboBoxDropdownTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindowViewModel ViewModel
        {
            get { return this.DataContext as MainWindowViewModel; }
        }

        public MainWindow()
        {
            InitializeComponent();
            var vm = new MainWindowViewModel();
            this.DataContext = vm;
            this.Loaded += OnLoaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            this.ViewModel.Initialize();
        }
    }
}

MainWindowViewModel.cs:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;

namespace ComboBoxDropdownTest
{
    public class MainWindowViewModel : ViewModelBase
    {
        private string selectedAtStartup;
        private bool isDropDownOpen;
        private ObservableCollection<WorksheetViewModel> worksheets;
        private bool loadedOnce;

        public MainWindowViewModel()
        {
            this.PropertyChanged += OnViewModelPropertyChanged;
        }

        public string Title { get => "This is a combobox dropdown test"; }

        public string SelectedAtStartup { get => this.selectedAtStartup; set { this.selectedAtStartup = value; OnPropertyChanged(); } }

        public bool IsDropDownOpen { get => this.isDropDownOpen; set { this.isDropDownOpen = value; OnPropertyChanged(); } }

        public WorksheetViewModel Worksheet
        {
            get { return this.Worksheets.FirstOrDefault(o => o.Selected); }
        }

        public ObservableCollection<WorksheetViewModel> Worksheets
        {
            get
            {
                if (this.worksheets == null)
                {
                    this.worksheets = new ObservableCollection<WorksheetViewModel>();
                }

                return this.worksheets;
            }
        }

        public void Initialize()
        {
            // Simulates the loading of your selected property at startup
            this.SelectedAtStartup = "Worksheet3";
        }

        private async Task LoadBACnetWsCombobox()
        {
            for (int i = 0; i < 10; i++)
            {
                var worksheet = new Worksheet() { Name = $"Worksheet{i}" };
                this.Worksheets.Add(new WorksheetViewModel(worksheet));
            }

            // simulate a long 2-second delay load time
            await Task.Delay(2000);
        }

        private async void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(this.IsDropDownOpen) && this.IsDropDownOpen)
            {
                // Do your Command action here
                if (!loadedOnce)
                {
                    this.loadedOnce = true;
                    await this.LoadBACnetWsCombobox();
                }
            }
        }
    }
}

WorksheetViewModel.cs:

namespace ComboBoxDropdownTest
{
    public class WorksheetViewModel : ViewModelBase<Worksheet>
    {
        public WorksheetViewModel(Worksheet model) : base(model)
        {
        }

        public string Name { get => this.Model.Name; set { this.Model.Name = value; OnPropertyChanged(); } }

        public override string ToString()
        {
            return this.Name;
        }
    }
}

ViewModelBase.cs:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace ComboBoxDropdownTest
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        private bool selected;

        public event PropertyChangedEventHandler PropertyChanged;

        public bool Selected { get => this.selected; set { this.selected = value; OnPropertyChanged(); } }

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class ViewModelBase<T> : ViewModelBase
    {
        public T Model { get; private set; }
        public ViewModelBase(T model) : base()
        {
            this.Model = model;
        }
    }
}

Worksheet.cs:

namespace ComboBoxDropdownTest
{
    public class Worksheet
    {
        public string Name { get; set; }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.