グラフをそのように表示するんですか。。。
通常折れ線グラフの横軸(今回は縦ですが)は時系列等の推移を見るもので、この例には向いていないように思います。
しかし別質問もありますし、それは置いておきます。
現状ある程度動いているのであれば、↓のような感じで開閉はできると思います。
xml
1<Canvas x:Name="DetailNm" Visibility="{Binding IsDetail}" />
2<Canvas x:Name="Detail" Visibility="{Binding IsDetail}" />
3
4 <!-- IsDetailがboolなら
5<Canvas x:Name="DetailNm" Visibility="{Binding IsDetail, Converter={StaticResource BooleanToVisibilityConverter}}" />
6<Canvas x:Name="Detail" Visibility="{Binding IsDetail, Converter={StaticResource BooleanToVisibilityConverter}}"/>
7-->
cs
1private void BtnDetail_Click(object sender, RoutedEventArgs e)
2{
3 if ((sender as Button)?.DataContext is Area area)
4 {
5 foreach (var a in AreaList) a.IsDetail = false;
6 area.IsDetail = true;
7 }
8}
RadioButton
を使えばコードビハインドいらずですみますが、すべて閉じることができなくなるので一長一短ですね。
この表示にこだわる場合は使えるかどうかちょっとわかりませんが、DataGrid
の行の詳細やグループ化で畳むような表現はあります。
方法: DataGrid コントロールに行の詳細を追加する - WPF .NET Framework | Microsoft Docs
方法: DataGrid コントロールでデータをグループ化、並べ替え、およびフィルター処理する - WPF .NET Framework | Microsoft Docs
xml
1<Window
2 x:Class="Questions311409.MainWindow"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5 Width="800"
6 Height="450">
7 <Window.Resources>
8 <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
9 <Style
10 x:Key="ButtonStyle"
11 BasedOn="{StaticResource {x:Type ToggleButton}}"
12 TargetType="{x:Type RadioButton}" />
13 </Window.Resources>
14
15 <Border
16 Margin="5"
17 Background="LightGray"
18 BorderBrush="Black"
19 BorderThickness="1">
20 <Grid>
21 <Grid.RowDefinitions>
22 <RowDefinition Height="50" />
23 <RowDefinition Height="*" />
24 <RowDefinition Height="Auto" />
25 </Grid.RowDefinitions>
26 <Grid.ColumnDefinitions>
27 <ColumnDefinition Width="Auto" />
28 <ColumnDefinition Width="*" />
29 </Grid.ColumnDefinitions>
30
31 <ScrollViewer
32 x:Name="ColumnHeader"
33 Grid.Column="1"
34 ScrollViewer.HorizontalScrollBarVisibility="Hidden"
35 ScrollViewer.VerticalScrollBarVisibility="Hidden">
36 <Border BorderBrush="DimGray" BorderThickness="1">
37 <StackPanel x:Name="YokoSenPanel" Orientation="Vertical" />
38 </Border>
39 </ScrollViewer>
40
41 <ScrollViewer
42 x:Name="RowHeader"
43 Grid.Row="1"
44 ScrollChanged="ScrollChanged"
45 ScrollViewer.HorizontalScrollBarVisibility="Hidden"
46 ScrollViewer.VerticalScrollBarVisibility="Hidden">
47 <ItemsControl x:Name="Test2" ItemsSource="{Binding AreaList}">
48 <ItemsControl.ItemTemplate>
49 <DataTemplate>
50 <Border
51 Padding="5"
52 BorderBrush="DimGray"
53 BorderThickness="1">
54 <StackPanel>
55 <StackPanel Orientation="Horizontal">
56 <Label x:Name="AreaName" Content="{Binding TenpoMei}" />
57 <RadioButton
58 Content="詳細"
59 GroupName="Area"
60 IsChecked="{Binding IsDetail}"
61 Style="{StaticResource ButtonStyle}" />
62 </StackPanel>
63 <ItemsControl
64 Margin="20,0,0,0"
65 ItemsSource="{Binding Items}"
66 Visibility="{Binding IsDetail, Converter={StaticResource BooleanToVisibilityConverter}}">
67 <ItemsControl.ItemTemplate>
68 <DataTemplate>
69 <TextBlock Text="{Binding ShouhinMei}" />
70 </DataTemplate>
71 </ItemsControl.ItemTemplate>
72 </ItemsControl>
73 </StackPanel>
74 </Border>
75 </DataTemplate>
76 </ItemsControl.ItemTemplate>
77 </ItemsControl>
78 </ScrollViewer>
79
80 <ScrollViewer
81 x:Name="AreaSenViewer"
82 Grid.Row="1"
83 Grid.RowSpan="2"
84 Grid.Column="1"
85 Background="White"
86 ScrollChanged="ScrollChanged"
87 ScrollViewer.HorizontalScrollBarVisibility="Auto"
88 ScrollViewer.VerticalScrollBarVisibility="Visible">
89 <ItemsControl
90 x:Name="Test"
91 AlternationCount="2"
92 ItemsSource="{Binding AreaList}">
93 <ItemsControl.ItemTemplate>
94 <DataTemplate>
95 <Border
96 Padding="5"
97 BorderBrush="DimGray"
98 BorderThickness="1">
99 <StackPanel HorizontalAlignment="Left">
100 <Grid>
101 <!-- 高さ合わせ用ダミー -->
102 <Label
103 x:Name="dummy"
104 Content="{Binding TenpoMei}"
105 Visibility="Hidden" />
106 <Canvas x:Name="Area" Width="{Binding Goukei}">
107 <Line
108 x:Name="Line"
109 Stroke="SkyBlue"
110 StrokeThickness="10"
111 X2="{Binding Goukei}"
112 Y1="16"
113 Y2="16" />
114 <TextBlock Text="{Binding Jyuni}" />
115 </Canvas>
116 </Grid>
117
118 <ItemsControl ItemsSource="{Binding Items}" Visibility="{Binding IsDetail, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}">
119 <ItemsControl.ItemTemplate>
120 <DataTemplate>
121 <Grid>
122 <Canvas x:Name="Detail">
123 <Line
124 HorizontalAlignment="Center"
125 VerticalAlignment="Center"
126 Stroke="YellowGreen"
127 StrokeThickness="10"
128 X2="{Binding Uriage}"
129 Y1="11"
130 Y2="11" />
131 </Canvas>
132 <TextBlock Text="{Binding Uriage}" />
133 </Grid>
134 </DataTemplate>
135 </ItemsControl.ItemTemplate>
136 </ItemsControl>
137 </StackPanel>
138 </Border>
139 </DataTemplate>
140 </ItemsControl.ItemTemplate>
141 </ItemsControl>
142 </ScrollViewer>
143
144 <!--
145 水平スクロールバー表示非表示時の位置合わせ用ダミー
146 微妙に表示タイミングがずれるが、ちゃんとやろうとするとかなり面倒
147 -->
148 <ScrollBar
149 Grid.Row="2"
150 Width="0"
151 Orientation="Horizontal"
152 Visibility="{Binding ComputedHorizontalScrollBarVisibility, ElementName=AreaSenViewer, Mode=OneWay}" />
153 </Grid>
154 </Border>
155</Window>
cs
1using System.Collections.Generic;
2using System.Collections.ObjectModel;
3using System.ComponentModel;
4using System.Linq;
5using System.Runtime.CompilerServices;
6using System.Windows;
7using System.Windows.Controls;
8
9namespace Questions311409
10{
11 public class Observable : INotifyPropertyChanged
12 {
13 public event PropertyChangedEventHandler PropertyChanged;
14 protected void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
15 {
16 if (Equals(storage, value)) return;
17 storage = value;
18 OnPropertyChanged(propertyName);
19 }
20 protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
21 }
22
23 public class Area : Observable
24 {
25 public string TenpoMei { get; }
26
27 public bool IsDetail { get => _IsDetail; set => Set(ref _IsDetail, value); }
28 private bool _IsDetail;
29
30 public string Jyuni { get; }
31
32 public int Goukei => Items.Sum(x => x.Uriage);
33
34 public List<Item> Items { get; } = new List<Item>();
35
36
37 public Area(string tenpoMei, string jyuni, params Item[] items)
38 {
39 TenpoMei = tenpoMei;
40 Jyuni = jyuni;
41
42 foreach (var item in items) Items.Add(item);
43 }
44 }
45
46 public class Item
47 {
48 public string ShouhinMei { get; }
49
50 public int Uriage { get; }
51
52 public Item(string shouhinMei, int uriage)
53 {
54 ShouhinMei = shouhinMei;
55 Uriage = uriage;
56 }
57 }
58
59 public partial class MainWindow : Window
60 {
61 public ObservableCollection<Area> AreaList { get; }
62
63 public MainWindow()
64 {
65 InitializeComponent();
66
67 AreaList = new ObservableCollection<Area>
68 {
69 new Area("A店","2位", new Item("商品1", 30), new Item("商品2", 100), new Item("商品3", 70)),
70 new Area("B店","1位", new Item("商品1", 50), new Item("商品2", 150), new Item("商品3", 100)),
71 new Area("C店","3位", new Item("商品1", 10), new Item("商品2", 60), new Item("商品4", 30)),
72 };
73
74 DataContext = this;
75 }
76
77 private void ScrollChanged(object sender, ScrollChangedEventArgs e)
78 {
79 if (sender == RowHeader)
80 {
81 AreaSenViewer.ScrollToVerticalOffset(e.VerticalOffset);
82 }
83 if (sender == AreaSenViewer)
84 {
85 RowHeader.ScrollToVerticalOffset(e.VerticalOffset);
86 }
87 }
88
89 private void BtnDetail_Click(object sender, RoutedEventArgs e)
90 {
91 if ((sender as Button)?.DataContext is Area area)
92 {
93 foreach (var a in AreaList) a.IsDetail = false;
94
95 area.IsDetail = true;
96 }
97 }
98 }
99}