c# - 使用 MVVM 模式从 ObservableCollection 添加按钮到 WPF

标签 c# wpf xaml mvvm dynamically-generated

我正在尝试向 UserControl 添加按钮。我必须遵循 MVVM 模式。我创建了一个类 DeviceButton,它具有不同的设置/获取和构造函数。在 View 模型中,用作数据上下文的是 ObservableCollection 和集合的获取方法。我已将集合绑定(bind)到 ItemsControl 源并尝试添加模板。我想我错过了什么,因为按钮无法加载。

UserControl 被添加到选项卡中(使用 dragablz ),它也是 ObservableCollection 的一部分,也是在运行时添加的(这工作得很好)。这个想法是,该选项卡有一个必须在运行时创建的按钮列表,其中该列表是从 Web 服务获取的 - 因此必须动态/以编程方式添加按钮。概述只是第一个选项卡 - 每个选项卡的模板(反射(reflect)获取的项目)在按钮工作时正在实现。现在,我只是在集合中添加一个测试按钮,但如前所述,这不会显示。我错过了什么?

我有一个 Overview.xaml 文件:

<UserControl // attributes omitted to save spaces... ask if needed>

<StackPanel>
    <Border>
        <TextBlock FontSize="16" FontWeight="Bold" TextWrapping="WrapWithOverflow"
                   TextAlignment="Center" HorizontalAlignment="Center"
                   Foreground="{DynamicResource AccentColorBrush}">
            Welcome to Greenhouse App
        </TextBlock>
    </Border>

    <ItemsControl ItemsSource="{Binding DeviceButtons}">
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type vmodel:DeviceButton}">
                <Button Width="50" Height="50" Margin="10 10 0 0" Command="{Binding OpenTab}"
                        CommandParameter="{Binding DeviceType}" HorizontalAlignment="Left"
                        VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}">
                    <StackPanel>
                        <Image Source="{Binding ImageUrl}" />
                    </StackPanel>
                </Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    // Manually added test button...
    <Button x:Name="windMill" HorizontalAlignment="Left" Margin="10,0,0,0"
            VerticalAlignment="Top" Width="50" Height="50"
            Command="{Binding OpenTab}" FontFamily="Segoe Ui"
            Style="{DynamicResource SquareButtonStyle}">
        <StackPanel>
            <Image Source="/Greenhouse;component/Icons/Windmill.png" />
        </StackPanel>
    </Button
</StackPanel>

我正在尝试添加 DeviceButton 类型的 ObservableCollection,即 _deviceButtons 集合(作为 ItemsSource 绑定(bind)到 ItemsControl)

tabList 项目只是找到了,如果需要我可以手动添加更多(这些稍后将通过 OpenNewTab 命令添加,应该绑定(bind)到按钮)

DeviceButton 文件:

public class DeviceButton
{
    private readonly string _content;
    private readonly string _deviceType;
    private readonly string _imageUrl;

    public DeviceButton(string content, string deviceType, string imageUrl)
    {
        _content = content;
        _deviceType = deviceType;
        _imageUrl = imageUrl;
    }

    public string Content
    {
        get { return _content; }
    }

    public string DeviceType
    {
        get { return _deviceType; }
    }

    public string ImageUrl
    {
        get { return _imageUrl; }
    }
}

该集合位于 View 模型文件 MainWindowViewModel.cs 中:

public class MainWindowViewModel : ViewModelBase, INotifyPropertyChanged
{
    public ICommand OpenTab { get; set; }

    private string tabControl { get; set; } = "0";
    private IInterTabClient _interTabClient;
    private ObservableCollection<TabContent> _tabContents = new ObservableCollection<TabContent>();
    private ObservableCollection<DeviceButton> _deviceButtons = new ObservableCollection<DeviceButton>();

    public MainWindowViewModel()
    {
        _interTabClient = new MyInterTabClient();

        DeviceButtons.Add(new DeviceButton("Windturbine", "windturbine", "/Greenhouse;component/Icons/Windmill.png"));

        TabContents.Add(new TabContent("Overview", new Overview()));

        OpenTab = new RelayCommand<object>(OpenNewTab);
    }

    private void OpenNewTab(object obj)
    {
        MessageBox.Show("Yo"); // Not yet implemented
        RaisePropertyChanged(() => tabControl);
    }

    public ObservableCollection<TabContent> TabContents
    {
        get { return _tabContents; }
    }

    public ObservableCollection<DeviceButton> DeviceButtons
    {
        get { return _deviceButtons; }
    }

    public IInterTabClient InterTabClient
    {
        get { return _interTabClient; }
    }
}

当我启动程序时没有加载按钮(只有在 WPF 中手动添加的“测试”按钮)。

UserControl,Overview,被认为是另一个 Controls.Metrowindow,MainWindow.xaml 中的选项卡:

<Window.Resources>
    <Style TargetType="{x:Type dragablz:TabablzControl}">
        <Setter Property="CustomHeaderItemTemplate">
            <Setter.Value>
                <DataTemplate DataType="{x:Type viewmodel:TabContent}">
                    <TextBlock Text="{Binding Header}" />
                </DataTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate DataType="{x:Type viewmodel:TabContent}">
                    <ContentPresenter Margin="4" Content="{Binding Content}" />
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<dragablz:TabablzControl SelectedIndex="{Binding tabControl}" ItemsSource="{Binding TabContents}" x:Name="InitialTabablzControl" Margin="4 0 4 4">
    <dragablz:TabablzControl.InterTabController>
        <dragablz:InterTabController InterTabClient="{Binding MyInterTabClient}" />
    </dragablz:TabablzControl.InterTabController>
</dragablz:TabablzControl>

我猜这是 Overview.xaml 中的资源/绑定(bind)问题,但我已经用尽了我能找到的所有建议解决方案。

最佳答案

问题在于绑定(bind)

ItemsSource="{Binding Path=DataContext.TabContents, 
              RelativeSource={RelativeSource AncestorLevel=1, 
              AncestorType={x:Type Window}, Mode=FindAncestor}}"

关于c# - 使用 MVVM 模式从 ObservableCollection 添加按钮到 WPF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34024521/

相关文章:

c# - 文件映射架构

c# - "foreach with task.Wait"和 Task.WaitAll 的区别

c# - 使用 Microsoft Graph API 获取 Outlook 中的所有消息

c# - 用于 lzo.net 的最新版本的 lzo.dll(内存压缩)

c# - INotifyPropertyChanged 不适用于传统绑定(bind),但适用于编译绑定(bind)

c# - 如何在 WPF 中保持可缩放、可滚动内容的纵横比?

c# - 路径几何中的圆

c# - 在具有 ui/非 ui 线程差异的 WPF 中使用 PInvoke

wpf - 使用 WPF MVVM 运行动画

c# - 与 UserControl 的双向绑定(bind)