TabControl/TabItems绑定

huangapple go评论192阅读模式
英文:

TabControl/TabItems bindings

问题

我有一个TabControl,它从对象列表中检索其TabItems。每个TabItem都有一个标题,该标题与相应对象的 "Name" 属性关联。每个TabItem的内容与包含其他属性的 "Settings" 属性连接在一起。

为了根据名为 "type" 的属性的类型实现不同的行为,我使用了数据触发器。例如,如果 "type" 属性设置为 "int",则显示一个TextBox,而如果设置为 "bool",则显示一个CheckBox。

然而,我遇到了一个问题,这种行为仅适用于列表中的一个特定类型。例如,只有一个类型,如 "string",才能正确显示TextBox,只有一个 "bool" 属性才能正确显示CheckBox。我无法确定这个问题的原因。

View Code:

<TabControl ItemsSource="{Binding ItemsSource}" >
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ItemsControl ItemsSource="{Binding Settings}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate&gt:

                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Name}" FontSize="17" Width="100" />
                                <ContentControl>
                                    <ContentControl.Style>
                                        <Style TargetType="ContentControl">
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding Type}" Value="string">
                                                    <Setter Property="Content">
                                                        <Setter.Value>
                                                            <TextBox Text="{Binding Value}" FontSize="17" Width="80" Margin="5"/>
                                                        </Setter.Value>
                                                    </Setter>
                                                </DataTrigger>

                                                <DataTrigger Binding="{Binding Type}" Value="int">
                                                    <Setter Property="Content">
                                                        <Setter.Value>
                                                            <TextBox Text="{Binding Value}"  Width="50" FontSize="17" Margin="5"/>
                                                        </Setter.Value>
                                                    </Setter>
                                                </DataTrigger>

                                                <DataTrigger Binding="{Binding Type}" Value="bool">
                                                    <Setter Property="Content">
                                                        <Setter.Value>
                                                            <CheckBox IsChecked="{Binding Value}" VerticalAlignment="Center" Margin="5"/>
                                                        </Setter.Value>
                                                    </Setter>
                                                </DataTrigger>
                                            </Style.Triggers>
                                        </Style>
                                    </ContentControl.Style>
                                </ContentControl>
                            </StackPanel>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>

然而,如果我避免使用DataTriggers,只对所有类型使用TextBox,它就能正常工作:

<TabControl TabStripPlacement="Left" ItemsSource="{Binding ItemsSource.Groups}" >
        <TabControl.ItemContainerStyle>
            <Style TargetType="TabItem" BasedOn="{StaticResource BaseTabItemsStyle}" />
        </TabControl.ItemContainerStyle>

        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ItemsControl ItemsSource="{Binding Settings}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>

                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Name}" FontSize="17" />
                                <TextBox Text="{Binding Value}" FontSize="17" />

                            </StackPanel>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>

ViewModel Code:

public class MainWindowViewModel : BindableBase
    {

        // My property
        private ObservableCollection<Group> itemsSource;
        public ObservableCollection<Group> ItemsSource
        {
            get { return itemsSource; }
            set { SetProperty(ref itemsSource, value); }
        }


        // Constructor
        public MainWindowViewModel()
        {
            SetConfigValues();
        }

        private void SetConfigValues()
        {
            // Create some settings
            var _settings1 = new Setting()
            {
                Name = "Host",
                Value = "localhost",
                Type = "string"
            };
            var _settings2 = new Setting()
            {
                Name = "Port",
                Value = "5432",
                Type = "int"
            };
            var _settings3 = new Setting()
            {
                Name = "AutoStart",
                Value = "true",
                Type = "bool"
            };

            // Set these settings to Items source
            ItemsSource = new ObservableCollection<Group>()
            {

                new Group()
                {
                    Name = "Header Tab 1",
                    Settings = new ObservableCollection<Setting>
                    {
                        _settings1,
                        _settings2,
                        _settings3,
                        _settings1,
                        _settings2,
                        _settings3
                    },
                },

                new Group()
                {
                    Name = "Header Tab 2",
                    Settings = new ObservableCollection&lt

<details>
<summary>英文:</summary>

I have a TabControl that retrieves its TabItems from a list of objects. Each TabItem has a header that is linked to the &quot;Name&quot; property of the corresponding object. The content of each TabItem is connected to the &quot;Settings&quot; property, which contains additional properties.

To achieve different behavior depending on the type of a property called &quot;type,&quot; I use data triggers. For example, if the &quot;type&quot; property is set to &quot;int,&quot; a TextBox is displayed, while if it&#39;s set to &quot;bool,&quot; a CheckBox is displayed instead.

However, I am encountering an issue where this behavior only works for one specific type within the  list. For instance, only one type, such as &quot;string,&quot; correctly displays the TextBox, and only one &quot;bool&quot; property correctly displays the CheckBox. I am unable to determine the cause of this issue.

View Code:

<TabControl ItemsSource="{Binding ItemsSource}" >
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Settings}">
<ItemsControl.ItemTemplate>
<DataTemplate>

                        &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
                            &lt;TextBlock Text=&quot;{Binding Name}&quot; FontSize=&quot;17&quot; Width=&quot;100&quot; /&gt;
                            &lt;ContentControl&gt;
                                &lt;ContentControl.Style&gt;
                                    &lt;Style TargetType=&quot;ContentControl&quot;&gt;
                                        &lt;Style.Triggers&gt;
                                            &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;string&quot;&gt;
                                                &lt;Setter Property=&quot;Content&quot;&gt;
                                                    &lt;Setter.Value&gt;
                                                        &lt;TextBox Text=&quot;{Binding Value}&quot; FontSize=&quot;17&quot; Width=&quot;80&quot; Margin=&quot;5&quot;/&gt;
                                                    &lt;/Setter.Value&gt;
                                                &lt;/Setter&gt;
                                            &lt;/DataTrigger&gt;

                                            &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;int&quot;&gt;
                                                &lt;Setter Property=&quot;Content&quot;&gt;
                                                    &lt;Setter.Value&gt;
                                                        &lt;TextBox Text=&quot;{Binding Value}&quot;  Width=&quot;50&quot; FontSize=&quot;17&quot; Margin=&quot;5&quot;/&gt;
                                                    &lt;/Setter.Value&gt;
                                                &lt;/Setter&gt;
                                            &lt;/DataTrigger&gt;

                                            &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;bool&quot;&gt;
                                                &lt;Setter Property=&quot;Content&quot;&gt;
                                                    &lt;Setter.Value&gt;
                                                        &lt;CheckBox IsChecked=&quot;{Binding Value}&quot; VerticalAlignment=&quot;Center&quot; Margin=&quot;5&quot;/&gt;
                                                    &lt;/Setter.Value&gt;
                                                &lt;/Setter&gt;
                                            &lt;/DataTrigger&gt;
                                        &lt;/Style.Triggers&gt;
                                    &lt;/Style&gt;
                                &lt;/ContentControl.Style&gt;
                            &lt;/ContentControl&gt;
                        &lt;/StackPanel&gt;
                    &lt;/DataTemplate&gt;
                &lt;/ItemsControl.ItemTemplate&gt;
            &lt;/ItemsControl&gt;
        &lt;/DataTemplate&gt;
    &lt;/TabControl.ContentTemplate&gt;
&lt;/TabControl&gt;

However, If I avoid the DataTriggers and I use only TextBox for all types, it works:


<TabControl TabStripPlacement="Left" ItemsSource="{Binding ItemsSource.Groups}" >
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem" BasedOn="{StaticResource BaseTabItemsStyle}" />
</TabControl.ItemContainerStyle>

    &lt;TabControl.ItemTemplate&gt;
        &lt;DataTemplate&gt;
            &lt;TextBlock Text=&quot;{Binding Name}&quot; /&gt;
        &lt;/DataTemplate&gt;
    &lt;/TabControl.ItemTemplate&gt;
    &lt;TabControl.ContentTemplate&gt;
        &lt;DataTemplate&gt;
            &lt;ItemsControl ItemsSource=&quot;{Binding Settings}&quot;&gt;
                &lt;ItemsControl.ItemTemplate&gt;
                    &lt;DataTemplate&gt;
                        
                        &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
                            &lt;TextBlock Text=&quot;{Binding Name}&quot; FontSize=&quot;17&quot; /&gt;
                            &lt;TextBox Text=&quot;{Binding Value}&quot; FontSize=&quot;17&quot; /&gt;
                            
                        &lt;/StackPanel&gt;
                    &lt;/DataTemplate&gt;
                &lt;/ItemsControl.ItemTemplate&gt;
            &lt;/ItemsControl&gt;
        &lt;/DataTemplate&gt;
    &lt;/TabControl.ContentTemplate&gt;
&lt;/TabControl&gt; 

ViewModel Code:

public class MainWindowViewModel : BindableBase
{

    // My property
    private ObservableCollection&lt;Group&gt; itemsSource;
    public ObservableCollection&lt;Group&gt; ItemsSource
    {
        get { return itemsSource; }
        set { SetProperty(ref itemsSource, value); }
    }


    // Constructor
    public MainWindowViewModel()
    {
        SetConfigValues();
    }

    private void SetConfigValues()
    {
        // Create some settings
        var _settings1 = new Setting()
        {
            Name = &quot;Host&quot;,
            Value = &quot;localhost&quot;,
            Type = &quot;string&quot;
        };
        var _settings2 = new Setting()
        {
            Name = &quot;Port&quot;,
            Value = &quot;5432&quot;,
            Type = &quot;int&quot;
        };
        var _settings3 = new Setting()
        {
            Name = &quot;AutoStart&quot;,
            Value = &quot;true&quot;,
            Type = &quot;bool&quot;
        };

        // Set these settings to Items source
        ItemsSource = new ObservableCollection&lt;Group&gt;()
        {

            new Group()
            {
                Name = &quot;Header Tab 1&quot;,
                Settings = new ObservableCollection&lt;Setting&gt;
                {
                    _settings1,
                    _settings2,
                    _settings3,
                    _settings1,
                    _settings2,
                    _settings3
                },
            },

            new Group()
            {
                Name = &quot;Header Tab 2&quot;,
                Settings = new ObservableCollection&lt;Setting&gt;
                {
                    _settings1,
                    _settings2,
                    _settings3,
                    _settings1,
                    _settings2,
                    _settings3
                },
            }
        };
    }

}

My Custom Classes (Where data comes from):

public class Group
{
public string Name { get; set; }
public ObservableCollection<Setting> Settings { get; set; }
}

public class Setting
{
    public string Type { get; set; }
    public string Value { get; set; }
    public string Name { get; set; }
}

What I get:

[![enter image description here][1]][1]

What I expect:
[![enter image description here][2]][2]


  [1]: https://i.stack.imgur.com/uGwpZ.png
  [2]: https://i.stack.imgur.com/yHuKJ.png

</details>


# 答案1
**得分**: 1

定义一个`DataTemplate`来表示每种类型,并在你的`Style`中设置`ContentTemplate`属性:

```xml
<ItemsControl ItemsSource="{Binding Settings}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <DataTemplate.Resources>
                <DataTemplate x:Key="stringTemplate">
                    <TextBox Text="{Binding Value}" FontSize="17" Width="80" Margin="5"/>
                </DataTemplate>
                <DataTemplate x:Key="intTemplate">
                    <TextBox Text="{Binding Value}" Width="50" FontSize="17" Margin="5"/>
                </DataTemplate>
                <DataTemplate x:Key="boolTemplate">
                    <CheckBox IsChecked="{Binding Value}" VerticalAlignment="Center" Margin="5"/>
                </DataTemplate>
            </DataTemplate.Resources>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" FontSize="17" Width="100" />
                <ContentControl Content="{Binding}">
                    <ContentControl.Style>
                        <Style TargetType="ContentControl">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Type}" Value="string">
                                    <Setter Property="ContentTemplate" Value="{StaticResource stringTemplate}"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Type}" Value="int">
                                    <Setter Property="ContentTemplate" Value="{StaticResource intTemplate}"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Type}" Value="bool">
                                    <Setter Property="ContentTemplate" Value="{StaticResource boolTemplate}"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </ContentControl.Style>
                </ContentControl>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

还要注意,我已经设置/绑定了ContentControlContent属性到Setting对象。一个ContentControl应该有一些Content以及一个ContentTemplate来可视化这个内容。

英文:

Define a DataTemplate per type and set the ContentTemplate property in your Style:

&lt;ItemsControl ItemsSource=&quot;{Binding Settings}&quot;&gt;
    &lt;ItemsControl.ItemTemplate&gt;
        &lt;DataTemplate&gt;
            &lt;DataTemplate.Resources&gt;
                &lt;DataTemplate x:Key=&quot;stringTemplate&quot;&gt;
                    &lt;TextBox Text=&quot;{Binding Value}&quot; FontSize=&quot;17&quot; Width=&quot;80&quot; Margin=&quot;5&quot;/&gt;
                &lt;/DataTemplate&gt;
                &lt;DataTemplate x:Key=&quot;intTemplate&quot;&gt;
                    &lt;TextBox Text=&quot;{Binding Value}&quot;  Width=&quot;50&quot; FontSize=&quot;17&quot; Margin=&quot;5&quot;/&gt;
                &lt;/DataTemplate&gt;
                &lt;DataTemplate x:Key=&quot;boolTemplate&quot;&gt;
                    &lt;CheckBox IsChecked=&quot;{Binding Value}&quot; VerticalAlignment=&quot;Center&quot; Margin=&quot;5&quot;/&gt;
                &lt;/DataTemplate&gt;
            &lt;/DataTemplate.Resources&gt;

            &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
                &lt;TextBlock Text=&quot;{Binding Name}&quot; FontSize=&quot;17&quot; Width=&quot;100&quot; /&gt;
                &lt;ContentControl Content=&quot;{Binding}&quot;&gt;
                    &lt;ContentControl.Style&gt;
                        &lt;Style TargetType=&quot;ContentControl&quot;&gt;
                            &lt;Style.Triggers&gt;
                                &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;string&quot;&gt;
                                    &lt;Setter Property=&quot;ContentTemplate&quot; Value=&quot;{StaticResource stringTemplate}&quot;/&gt;
                                &lt;/DataTrigger&gt;

                                &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;int&quot;&gt;
                                    &lt;Setter Property=&quot;ContentTemplate&quot; Value=&quot;{StaticResource intTemplate}&quot;/&gt;
                                &lt;/DataTrigger&gt;

                                &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;bool&quot;&gt;
                                    &lt;Setter Property=&quot;ContentTemplate&quot; Value=&quot;{StaticResource boolTemplate}&quot;/&gt;
                                &lt;/DataTrigger&gt;
                            &lt;/Style.Triggers&gt;
                        &lt;/Style&gt;
                    &lt;/ContentControl.Style&gt;
                &lt;/ContentControl&gt;
            &lt;/StackPanel&gt;
        &lt;/DataTemplate&gt;
    &lt;/ItemsControl.ItemTemplate&gt;
&lt;/ItemsControl&gt;

Also note that I've set/bound the Content property of the ContentControl to the Setting object. A ContentControl is supposed to have some Content and a ContentTemplate to visualize this content.

huangapple
  • 本文由 发表于 2023年6月5日 22:01:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76407208.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定