使用 MVVM 模式从 ObservableCollection 添加按钮到 WPF
Adding buttons to WPF from ObservableCollection using MVVM pattern
我正在尝试向 UserControl 添加按钮。我必须遵循 MVVM 模式。我创建了一个 class、DeviceButton,具有不同的 set/gets 和一个构造函数。在视图模型中,用作数据上下文的是 ObservableCollection 和集合的获取方法。我已将集合绑定到 ItemsControl 源并尝试添加模板。我想我遗漏了一些东西,因为按钮无法加载。
UserControl 被添加到选项卡中(使用 dragablz),它也是 ObservableCollection 的一部分,也是在 运行 时添加的(这工作得很好)。这个想法是,该选项卡有一个必须在 运行 时创建的按钮列表,该列表是从 Web 服务获取的 - 因此必须添加按钮 dynamically/programatically。概述只是第一个选项卡 - 每个选项卡的模板(反映获取的项目)在按钮工作时正在实施。现在,我只是在集合中添加一个测试按钮,但如前所述,这不会显示。我错过了什么?
我有一个 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 绑定到 ItemsControl)
tabList 项正在查找,如果需要我可以手动添加更多(稍后将通过 OpenNewTab 命令添加,应该绑定到按钮)
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; }
}
}
集合位于视图模型文件中,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; }
}
}
当我启动程序时没有加载按钮(只有 "test" 按钮在 WPF 中手动添加)。
用户控件概览被视为另一个 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 中的 resources/binding 的问题,但我已经用尽了我能找到的所有建议解决方案。
我怀疑 DataContext
被设置为一个 TabContent
对象,它没有 DeviceButtons
属性
我建议使用 Snoop 之类的工具来验证您的 DataContext
是否符合您的预期。
问题在于绑定
ItemsSource="{Binding Path=DataContext.TabContents,
RelativeSource={RelativeSource AncestorLevel=1,
AncestorType={x:Type Window}, Mode=FindAncestor}}"
我正在尝试向 UserControl 添加按钮。我必须遵循 MVVM 模式。我创建了一个 class、DeviceButton,具有不同的 set/gets 和一个构造函数。在视图模型中,用作数据上下文的是 ObservableCollection 和集合的获取方法。我已将集合绑定到 ItemsControl 源并尝试添加模板。我想我遗漏了一些东西,因为按钮无法加载。
UserControl 被添加到选项卡中(使用 dragablz),它也是 ObservableCollection 的一部分,也是在 运行 时添加的(这工作得很好)。这个想法是,该选项卡有一个必须在 运行 时创建的按钮列表,该列表是从 Web 服务获取的 - 因此必须添加按钮 dynamically/programatically。概述只是第一个选项卡 - 每个选项卡的模板(反映获取的项目)在按钮工作时正在实施。现在,我只是在集合中添加一个测试按钮,但如前所述,这不会显示。我错过了什么?
我有一个 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 绑定到 ItemsControl)
tabList 项正在查找,如果需要我可以手动添加更多(稍后将通过 OpenNewTab 命令添加,应该绑定到按钮)
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; }
}
}
集合位于视图模型文件中,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; }
}
}
当我启动程序时没有加载按钮(只有 "test" 按钮在 WPF 中手动添加)。
用户控件概览被视为另一个 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 中的 resources/binding 的问题,但我已经用尽了我能找到的所有建议解决方案。
我怀疑 DataContext
被设置为一个 TabContent
对象,它没有 DeviceButtons
属性
我建议使用 Snoop 之类的工具来验证您的 DataContext
是否符合您的预期。
问题在于绑定
ItemsSource="{Binding Path=DataContext.TabContents,
RelativeSource={RelativeSource AncestorLevel=1,
AncestorType={x:Type Window}, Mode=FindAncestor}}"