TabControl/TabItems绑定

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

TabControl/TabItems bindings

问题

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

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

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

View Code:

  1. <TabControl ItemsSource="{Binding ItemsSource}" >
  2. <TabControl.ItemTemplate>
  3. <DataTemplate>
  4. <TextBlock Text="{Binding Name}" />
  5. </DataTemplate>
  6. </TabControl.ItemTemplate>
  7. <TabControl.ContentTemplate>
  8. <DataTemplate>
  9. <ItemsControl ItemsSource="{Binding Settings}">
  10. <ItemsControl.ItemTemplate>
  11. <DataTemplate&gt:
  12. <StackPanel Orientation="Horizontal">
  13. <TextBlock Text="{Binding Name}" FontSize="17" Width="100" />
  14. <ContentControl>
  15. <ContentControl.Style>
  16. <Style TargetType="ContentControl">
  17. <Style.Triggers>
  18. <DataTrigger Binding="{Binding Type}" Value="string">
  19. <Setter Property="Content">
  20. <Setter.Value>
  21. <TextBox Text="{Binding Value}" FontSize="17" Width="80" Margin="5"/>
  22. </Setter.Value>
  23. </Setter>
  24. </DataTrigger>
  25. <DataTrigger Binding="{Binding Type}" Value="int">
  26. <Setter Property="Content">
  27. <Setter.Value>
  28. <TextBox Text="{Binding Value}" Width="50" FontSize="17" Margin="5"/>
  29. </Setter.Value>
  30. </Setter>
  31. </DataTrigger>
  32. <DataTrigger Binding="{Binding Type}" Value="bool">
  33. <Setter Property="Content">
  34. <Setter.Value>
  35. <CheckBox IsChecked="{Binding Value}" VerticalAlignment="Center" Margin="5"/>
  36. </Setter.Value>
  37. </Setter>
  38. </DataTrigger>
  39. </Style.Triggers>
  40. </Style>
  41. </ContentControl.Style>
  42. </ContentControl>
  43. </StackPanel>
  44. </DataTemplate>
  45. </ItemsControl.ItemTemplate>
  46. </ItemsControl>
  47. </DataTemplate>
  48. </TabControl.ContentTemplate>
  49. </TabControl>

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

  1. <TabControl TabStripPlacement="Left" ItemsSource="{Binding ItemsSource.Groups}" >
  2. <TabControl.ItemContainerStyle>
  3. <Style TargetType="TabItem" BasedOn="{StaticResource BaseTabItemsStyle}" />
  4. </TabControl.ItemContainerStyle>
  5. <TabControl.ItemTemplate>
  6. <DataTemplate>
  7. <TextBlock Text="{Binding Name}" />
  8. </DataTemplate>
  9. </TabControl.ItemTemplate>
  10. <TabControl.ContentTemplate>
  11. <DataTemplate>
  12. <ItemsControl ItemsSource="{Binding Settings}">
  13. <ItemsControl.ItemTemplate>
  14. <DataTemplate>
  15. <StackPanel Orientation="Horizontal">
  16. <TextBlock Text="{Binding Name}" FontSize="17" />
  17. <TextBox Text="{Binding Value}" FontSize="17" />
  18. </StackPanel>
  19. </DataTemplate>
  20. </ItemsControl.ItemTemplate>
  21. </ItemsControl>
  22. </DataTemplate>
  23. </TabControl.ContentTemplate>
  24. </TabControl>

ViewModel Code:

  1. public class MainWindowViewModel : BindableBase
  2. {
  3. // My property
  4. private ObservableCollection<Group> itemsSource;
  5. public ObservableCollection<Group> ItemsSource
  6. {
  7. get { return itemsSource; }
  8. set { SetProperty(ref itemsSource, value); }
  9. }
  10. // Constructor
  11. public MainWindowViewModel()
  12. {
  13. SetConfigValues();
  14. }
  15. private void SetConfigValues()
  16. {
  17. // Create some settings
  18. var _settings1 = new Setting()
  19. {
  20. Name = "Host",
  21. Value = "localhost",
  22. Type = "string"
  23. };
  24. var _settings2 = new Setting()
  25. {
  26. Name = "Port",
  27. Value = "5432",
  28. Type = "int"
  29. };
  30. var _settings3 = new Setting()
  31. {
  32. Name = "AutoStart",
  33. Value = "true",
  34. Type = "bool"
  35. };
  36. // Set these settings to Items source
  37. ItemsSource = new ObservableCollection<Group>()
  38. {
  39. new Group()
  40. {
  41. Name = "Header Tab 1",
  42. Settings = new ObservableCollection<Setting>
  43. {
  44. _settings1,
  45. _settings2,
  46. _settings3,
  47. _settings1,
  48. _settings2,
  49. _settings3
  50. },
  51. },
  52. new Group()
  53. {
  54. Name = "Header Tab 2",
  55. Settings = new ObservableCollection&lt
  56. <details>
  57. <summary>英文:</summary>
  58. 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.
  59. 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.
  60. 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.
  61. 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>

  1. &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
  2. &lt;TextBlock Text=&quot;{Binding Name}&quot; FontSize=&quot;17&quot; Width=&quot;100&quot; /&gt;
  3. &lt;ContentControl&gt;
  4. &lt;ContentControl.Style&gt;
  5. &lt;Style TargetType=&quot;ContentControl&quot;&gt;
  6. &lt;Style.Triggers&gt;
  7. &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;string&quot;&gt;
  8. &lt;Setter Property=&quot;Content&quot;&gt;
  9. &lt;Setter.Value&gt;
  10. &lt;TextBox Text=&quot;{Binding Value}&quot; FontSize=&quot;17&quot; Width=&quot;80&quot; Margin=&quot;5&quot;/&gt;
  11. &lt;/Setter.Value&gt;
  12. &lt;/Setter&gt;
  13. &lt;/DataTrigger&gt;
  14. &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;int&quot;&gt;
  15. &lt;Setter Property=&quot;Content&quot;&gt;
  16. &lt;Setter.Value&gt;
  17. &lt;TextBox Text=&quot;{Binding Value}&quot; Width=&quot;50&quot; FontSize=&quot;17&quot; Margin=&quot;5&quot;/&gt;
  18. &lt;/Setter.Value&gt;
  19. &lt;/Setter&gt;
  20. &lt;/DataTrigger&gt;
  21. &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;bool&quot;&gt;
  22. &lt;Setter Property=&quot;Content&quot;&gt;
  23. &lt;Setter.Value&gt;
  24. &lt;CheckBox IsChecked=&quot;{Binding Value}&quot; VerticalAlignment=&quot;Center&quot; Margin=&quot;5&quot;/&gt;
  25. &lt;/Setter.Value&gt;
  26. &lt;/Setter&gt;
  27. &lt;/DataTrigger&gt;
  28. &lt;/Style.Triggers&gt;
  29. &lt;/Style&gt;
  30. &lt;/ContentControl.Style&gt;
  31. &lt;/ContentControl&gt;
  32. &lt;/StackPanel&gt;
  33. &lt;/DataTemplate&gt;
  34. &lt;/ItemsControl.ItemTemplate&gt;
  35. &lt;/ItemsControl&gt;
  36. &lt;/DataTemplate&gt;
  37. &lt;/TabControl.ContentTemplate&gt;
  38. &lt;/TabControl&gt;
  1. 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>

  1. &lt;TabControl.ItemTemplate&gt;
  2. &lt;DataTemplate&gt;
  3. &lt;TextBlock Text=&quot;{Binding Name}&quot; /&gt;
  4. &lt;/DataTemplate&gt;
  5. &lt;/TabControl.ItemTemplate&gt;
  6. &lt;TabControl.ContentTemplate&gt;
  7. &lt;DataTemplate&gt;
  8. &lt;ItemsControl ItemsSource=&quot;{Binding Settings}&quot;&gt;
  9. &lt;ItemsControl.ItemTemplate&gt;
  10. &lt;DataTemplate&gt;
  11. &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
  12. &lt;TextBlock Text=&quot;{Binding Name}&quot; FontSize=&quot;17&quot; /&gt;
  13. &lt;TextBox Text=&quot;{Binding Value}&quot; FontSize=&quot;17&quot; /&gt;
  14. &lt;/StackPanel&gt;
  15. &lt;/DataTemplate&gt;
  16. &lt;/ItemsControl.ItemTemplate&gt;
  17. &lt;/ItemsControl&gt;
  18. &lt;/DataTemplate&gt;
  19. &lt;/TabControl.ContentTemplate&gt;
  20. &lt;/TabControl&gt;
  1. ViewModel Code:

public class MainWindowViewModel : BindableBase
{

  1. // My property
  2. private ObservableCollection&lt;Group&gt; itemsSource;
  3. public ObservableCollection&lt;Group&gt; ItemsSource
  4. {
  5. get { return itemsSource; }
  6. set { SetProperty(ref itemsSource, value); }
  7. }
  8. // Constructor
  9. public MainWindowViewModel()
  10. {
  11. SetConfigValues();
  12. }
  13. private void SetConfigValues()
  14. {
  15. // Create some settings
  16. var _settings1 = new Setting()
  17. {
  18. Name = &quot;Host&quot;,
  19. Value = &quot;localhost&quot;,
  20. Type = &quot;string&quot;
  21. };
  22. var _settings2 = new Setting()
  23. {
  24. Name = &quot;Port&quot;,
  25. Value = &quot;5432&quot;,
  26. Type = &quot;int&quot;
  27. };
  28. var _settings3 = new Setting()
  29. {
  30. Name = &quot;AutoStart&quot;,
  31. Value = &quot;true&quot;,
  32. Type = &quot;bool&quot;
  33. };
  34. // Set these settings to Items source
  35. ItemsSource = new ObservableCollection&lt;Group&gt;()
  36. {
  37. new Group()
  38. {
  39. Name = &quot;Header Tab 1&quot;,
  40. Settings = new ObservableCollection&lt;Setting&gt;
  41. {
  42. _settings1,
  43. _settings2,
  44. _settings3,
  45. _settings1,
  46. _settings2,
  47. _settings3
  48. },
  49. },
  50. new Group()
  51. {
  52. Name = &quot;Header Tab 2&quot;,
  53. Settings = new ObservableCollection&lt;Setting&gt;
  54. {
  55. _settings1,
  56. _settings2,
  57. _settings3,
  58. _settings1,
  59. _settings2,
  60. _settings3
  61. },
  62. }
  63. };
  64. }
  65. }
  1. My Custom Classes (Where data comes from):

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

  1. public class Setting
  2. {
  3. public string Type { get; set; }
  4. public string Value { get; set; }
  5. public string Name { get; set; }
  6. }
  1. What I get:
  2. [![enter image description here][1]][1]
  3. What I expect:
  4. [![enter image description here][2]][2]
  5. [1]: https://i.stack.imgur.com/uGwpZ.png
  6. [2]: https://i.stack.imgur.com/yHuKJ.png
  7. </details>
  8. # 答案1
  9. **得分**: 1
  10. 定义一个`DataTemplate`来表示每种类型,并在你的`Style`中设置`ContentTemplate`属性:
  11. ```xml
  12. <ItemsControl ItemsSource="{Binding Settings}">
  13. <ItemsControl.ItemTemplate>
  14. <DataTemplate>
  15. <DataTemplate.Resources>
  16. <DataTemplate x:Key="stringTemplate">
  17. <TextBox Text="{Binding Value}" FontSize="17" Width="80" Margin="5"/>
  18. </DataTemplate>
  19. <DataTemplate x:Key="intTemplate">
  20. <TextBox Text="{Binding Value}" Width="50" FontSize="17" Margin="5"/>
  21. </DataTemplate>
  22. <DataTemplate x:Key="boolTemplate">
  23. <CheckBox IsChecked="{Binding Value}" VerticalAlignment="Center" Margin="5"/>
  24. </DataTemplate>
  25. </DataTemplate.Resources>
  26. <StackPanel Orientation="Horizontal">
  27. <TextBlock Text="{Binding Name}" FontSize="17" Width="100" />
  28. <ContentControl Content="{Binding}">
  29. <ContentControl.Style>
  30. <Style TargetType="ContentControl">
  31. <Style.Triggers>
  32. <DataTrigger Binding="{Binding Type}" Value="string">
  33. <Setter Property="ContentTemplate" Value="{StaticResource stringTemplate}"/>
  34. </DataTrigger>
  35. <DataTrigger Binding="{Binding Type}" Value="int">
  36. <Setter Property="ContentTemplate" Value="{StaticResource intTemplate}"/>
  37. </DataTrigger>
  38. <DataTrigger Binding="{Binding Type}" Value="bool">
  39. <Setter Property="ContentTemplate" Value="{StaticResource boolTemplate}"/>
  40. </DataTrigger>
  41. </Style.Triggers>
  42. </Style>
  43. </ContentControl.Style>
  44. </ContentControl>
  45. </StackPanel>
  46. </DataTemplate>
  47. </ItemsControl.ItemTemplate>
  48. </ItemsControl>

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

英文:

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

  1. &lt;ItemsControl ItemsSource=&quot;{Binding Settings}&quot;&gt;
  2. &lt;ItemsControl.ItemTemplate&gt;
  3. &lt;DataTemplate&gt;
  4. &lt;DataTemplate.Resources&gt;
  5. &lt;DataTemplate x:Key=&quot;stringTemplate&quot;&gt;
  6. &lt;TextBox Text=&quot;{Binding Value}&quot; FontSize=&quot;17&quot; Width=&quot;80&quot; Margin=&quot;5&quot;/&gt;
  7. &lt;/DataTemplate&gt;
  8. &lt;DataTemplate x:Key=&quot;intTemplate&quot;&gt;
  9. &lt;TextBox Text=&quot;{Binding Value}&quot; Width=&quot;50&quot; FontSize=&quot;17&quot; Margin=&quot;5&quot;/&gt;
  10. &lt;/DataTemplate&gt;
  11. &lt;DataTemplate x:Key=&quot;boolTemplate&quot;&gt;
  12. &lt;CheckBox IsChecked=&quot;{Binding Value}&quot; VerticalAlignment=&quot;Center&quot; Margin=&quot;5&quot;/&gt;
  13. &lt;/DataTemplate&gt;
  14. &lt;/DataTemplate.Resources&gt;
  15. &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
  16. &lt;TextBlock Text=&quot;{Binding Name}&quot; FontSize=&quot;17&quot; Width=&quot;100&quot; /&gt;
  17. &lt;ContentControl Content=&quot;{Binding}&quot;&gt;
  18. &lt;ContentControl.Style&gt;
  19. &lt;Style TargetType=&quot;ContentControl&quot;&gt;
  20. &lt;Style.Triggers&gt;
  21. &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;string&quot;&gt;
  22. &lt;Setter Property=&quot;ContentTemplate&quot; Value=&quot;{StaticResource stringTemplate}&quot;/&gt;
  23. &lt;/DataTrigger&gt;
  24. &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;int&quot;&gt;
  25. &lt;Setter Property=&quot;ContentTemplate&quot; Value=&quot;{StaticResource intTemplate}&quot;/&gt;
  26. &lt;/DataTrigger&gt;
  27. &lt;DataTrigger Binding=&quot;{Binding Type}&quot; Value=&quot;bool&quot;&gt;
  28. &lt;Setter Property=&quot;ContentTemplate&quot; Value=&quot;{StaticResource boolTemplate}&quot;/&gt;
  29. &lt;/DataTrigger&gt;
  30. &lt;/Style.Triggers&gt;
  31. &lt;/Style&gt;
  32. &lt;/ContentControl.Style&gt;
  33. &lt;/ContentControl&gt;
  34. &lt;/StackPanel&gt;
  35. &lt;/DataTemplate&gt;
  36. &lt;/ItemsControl.ItemTemplate&gt;
  37. &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:

确定