TabControl/TabItems绑定

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

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:

确定