英文:
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>:
<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<
<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 "Name" property of the corresponding object. The content of each TabItem is connected to the "Settings" property, which contains additional properties.
To achieve different behavior depending on the type of a property called "type," I use data triggers. For example, if the "type" property is set to "int," a TextBox is displayed, while if it's set to "bool," 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 "string," correctly displays the TextBox, and only one "bool" 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>
<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>
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>
<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<Setting>
{
_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>
还要注意,我已经设置/绑定了ContentControl
的Content
属性到Setting
对象。一个ContentControl
应该有一些Content
以及一个ContentTemplate
来可视化这个内容。
英文:
Define a DataTemplate
per type and set the ContentTemplate
property in your Style
:
<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>
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论