数据绑定DataTemplate中的ItemsControl

普特尔

我似乎有一个简单的数据绑定问题,但找不到正确的方法来解决。有一个TabControl定义两个DataTemplate,一个用于标签标题,一个用于标签内容。

内容模板包含一个ItemsControlItemsControl尝试绑定到动态创建的ViewModel(ConnectionInfoVM)。

当我显示UI时,绑定只是失败,但是关于它的输出中没有错误消息。

我必须如何设置DataContext和绑定,以便绑定起作用并实际显示DataBuffer?任何帮助,不胜感激。

ConnectionsControl:

<UserControl x:Class="XXXViewer.Views.ConnectionsControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:viewModels="clr-namespace:XXXViewer.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid> 
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TabControl Grid.Row="0" Name="TabDynamic" SelectionChanged="tabDynamic_SelectionChanged">
            <TabControl.Resources>
                <DataTemplate x:Key="TabHeader" DataType="TabItem">
                    <DockPanel>
                        <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}" />
                        <Button Name="btnDelete" DockPanel.Dock="Right" Margin="5,0,0,0" Padding="0" Click="btnTabDelete_Click" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}">
                            <Image Source="{DynamicResource DeleteImg}" Height="11" Width="11"></Image>
                        </Button>
                    </DockPanel>
                </DataTemplate>

                <DataTemplate x:Key="TabContent" DataType="viewModels:ConnectionInfoVM">
                    <StackPanel>
                        <ScrollViewer Name="Scroller" Background="Black">
                            <StackPanel>
                                <TextBlock Text="This line gets printed" Foreground="White" FontFamily="Consolas"/>
                                <ItemsControl Name="ItemCtrl" ItemsSource="{Binding DataBuffer}">
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <TextBlock Text="{Binding Path=.}" Foreground="White" FontFamily="Consolas"/>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>
                            </StackPanel>
                        </ScrollViewer>
                    </StackPanel>
                </DataTemplate>

            </TabControl.Resources>
        </TabControl>
    </Grid>
</UserControl>

Connections后面的控制代码:

namespace XXXViewer.Views
{
    public partial class ConnectionsControl : UserControl
    {
        private readonly ObservableCollection<TabItem> _tabItems = new ObservableCollection<TabItem>();

        public ConnectionsControl()
        {
            InitializeComponent();

            // bindings
            TabDynamic.ItemsSource = _tabItems;
            TabDynamic.DataContext = this;
        }

        // assume this gets called
        private void AddTabItem(ConnectionInfoVM ci)
        {
            DataTemplate headerTemplate = TabDynamic.FindResource("TabHeader") as DataTemplate;
            DataTemplate contentTemplate = TabDynamic.FindResource("TabContent") as DataTemplate;

            // create new tab item
            TabItem tab = new TabItem
            {
                Header = $"Tab {ci.ConnectionID}",
                Name = $"T{ci.ConnectionID}",
                HeaderTemplate = headerTemplate,
                ContentTemplate = contentTemplate,
                DataContext = ci
            };

            _tabItems.Insert(0, tab);

            // set the new tab as active tab
            TabDynamic.SelectedItem = tab;
        }
    }
}

ConnectionInfoVM:

namespace XXXViewer.ViewModels
{
    public class ConnectionInfoVM : ViewModelBase
    {
        private readonly ObservableQueue<string> _dataBuffer = new ObservableQueue<string>();
        public ObservableQueue<string> DataBuffer => _dataBuffer;
    }
}

创建的选项卡的屏幕快照:结果选项卡

nkoniishvt

您设置了ContentTemplate但未设置Content,因此ContentTemplate永远不会应用,因为只有在设置Content时才应用ContentTemplate。而不是DataContext = ciContent = ci

顺便说一句,它DataContext = ci是无用的,因为DataContext已经隐式地是应用了DataTemplate的对象。

编辑

使用WPF时,请使用和滥用其核心功能:绑定。

我将如何编写您的代码(如果我不使用完整的MVVM兼容代码):

您的XAML:

<TabControl Grid.Row="0" Name="TabDynamic" 
            ItemsSource="{Binding TabItems, Mode=OneWay}" 
            SelectionChanged="tabDynamic_SelectionChanged">
    <TabControl.Resources>
        <DataTemplate x:Key="TabHeader" DataType="TabItem">
            <DockPanel>
                <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Header}" />
                <Button Name="btnDelete" DockPanel.Dock="Right" Margin="5,0,0,0" Padding="0" Click="btnTabDelete_Click" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Name}">
                    <Image Source="{DynamicResource DeleteImg}" Height="11" Width="11"></Image>
                </Button>
            </DockPanel>
        </DataTemplate>
    </TabControl.Resources>
    <TabControl.ItemTemplate>
        <DataTemplate DataType="viewModels:ConnectionInfoVM">
            <TabItem Header="{Binding ConnectionID, Mode=OneWay}"
                     Name="{Binding ConnectionID, Mode=OneWay}"
                     HeaderTemplate="{StaticResources TabHeader}">
                <StackPanel>
                    <ScrollViewer Name="Scroller" Background="Black">
                        <StackPanel>
                            <TextBlock Text="This line gets printed" Foreground="White" FontFamily="Consolas"/>
                            <ItemsControl Name="ItemCtrl" ItemsSource="{Binding DataBuffer}">
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=.}" Foreground="White" FontFamily="Consolas"/>
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </StackPanel>
                    </ScrollViewer>
                </StackPanel>
            </TabItem>

        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

您的cs代码变得更加简单:

namespace XXXViewer.Views
{
    public partial class ConnectionsControl : UserControl
    {
        private readonly ObservableCollection<ConnectionInfoVM> _tabItems = new ObservableCollection<ConnectionInfoVM>();
        public ObservableCollection<ConnectionInfoVM> TabItems {get {return _tabItems;}}

        public ConnectionsControl()
        {
            InitializeComponent();

            // bindings
            //TabDynamic.ItemsSource = _tabItems;
            TabDynamic.DataContext = this;
        }

        // assume this gets called
        private void AddTabItem(ConnectionInfoVM ci)
        {
            TabItems.Add(ci);
        }
    }
}

我在重新阅读代码时注意到,您可能对代码隐藏中的绑定感到困惑。

您的代码TabDynamic.ItemsSource = _tabItems;不是绑定,它只会设置一次。

无论如何,我建议您阅读一些有关MVVM的知识。TabItems应该在ViewModel类中,而不是在代码隐藏中。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章