トップ回答者
TreeViewを折り返して表示させることは可能でしょうか?

質問
-
いつもお世話になっています。
あまり見慣れないコントロールだとは思うのですが、TreeViewを折り返して表示できるようにしたいと考えています。
ひとまず、TreeView、TreeViewItem両方のItemsPanelを
<ItemPanelTemplate><WrapPanel Orientation="Vertical"/></ItemPanelTemplate>
とし、
TreeViewに ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
を定義することで、それらしい動きをするようになったのですが、一つ問題がありました。
下記のようなデータをTreeViewに表示するとします。
<items> <item value="1"> <item value="1.1"> <item value="1.1.1"/> <item value="1.1.2"/> <item value="1.1.3"/> </item> <item value="1.2"> <item value="1.2.1"/> <item value="1.2.2"/> <item value="1.2.3"/> </item> </item> <item value="2"> <item value="2.1"> <item value="2.1.1"/> </item> </item> <item value="3"> <item value="3.1"> <item value="3.1.1"/> <item value="3.1.2"/> </item> </item> </items>
8項目までレイアウトできる高さだとした場合、”1.2.3”は1列目にはレイアウトできないので、"1.2"が折り返され2列目に、"1.1"と同じ高さからレイアウトされます。
ただし、そうした場合に、1列目には3項目分の空きがあるため、"2"から"2.1.1"が1列目にレイアウトされてしまいます。(下図の現状をご参照ください)
WrapPanelの動作を考えるといたしかたないことなのですが、その様にレイアウトされてしまうと、"2.1.1"の続きが"1.2"であるかのように見えてしまい困っています。
下図Aのように"2"は3列目に表示されてほしいのですが、何か方法はありますでしょうか。
また、TreeViewでは実現できそうにないとは思うのですが、下図Bのように"1.2.2"まで1列目にレイアウトされ、"1.2.3"が2列目に、"1"と同じ高さからレイアウトされ、その続きに"2"~"3.1.2"までがレイアウトされる、というコントロールがあれば、理想的です。
よろしくお願いいたします。
回答
-
Bのように表示するだけなら左にマージンと展開用のボタンを付けるだけですけどね。
<ItemsControl ItemsSource="{Binding Collection}" > <ItemsControl.Resources> <app:LevelMarginConverter x:Key="conv" xmlns:app="clr-namespace:WpfApplication1"/> </ItemsControl.Resources> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Vertical" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Margin="{Binding Path=Level,Converter={StaticResource conv},ConverterParameter=10}"> <ToggleButton IsChecked="{Binding Path=IsExpand}" x:Name="tgl" Width="10" Height="10" IsEnabled="{Binding Path=CanExpand}" > </ToggleButton> <TextBlock Text="{Binding Item.Value}" /> </StackPanel> <DataTemplate.Triggers> <DataTrigger Binding="{Binding CanExpand}" Value="false" > <Setter TargetName="tgl" Property="Visibility" Value="Hidden" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
public partial class Window1 : Window { public Window1() { InitializeComponent(); var flat = FlatItem.Create(TestValue.CreateTestData()); this.DataContext = flat; } } class TestValue { public TestValue() { Items = new List<TestValue>(); } public string Value { get; set; } public List<TestValue> Items { get; private set; } public static TestValue CreateTestData() { TestValue lv0 = new TestValue(); lv0.Value = "ルート"; for (int i = 1; i <= 5; i++) { TestValue lv1 = new TestValue(); lv1.Value = i.ToString(); for (int j = 1; j <= 2; j++) { TestValue lv2 = new TestValue(); lv2.Value = lv1.Value + "." + j.ToString(); for (int k = 1; k <= 10; k++) { TestValue lv3 = new TestValue(); lv3.Value = lv2.Value + "." + k.ToString(); lv2.Items.Add(lv3); } lv1.Items.Add(lv2); } lv0.Items.Add(lv1); } return lv0; } } abstract class FratWrapperItem<T,U> : INotifyPropertyChanged { public FratWrapperItem(int level , T item, ObservableCollection<object> collection) { this.Items = new List<U>(); this.Level = level; this.Item = item; this._Collection = collection; } public ObservableCollection<object> Collection { get { return _Collection; } } private ObservableCollection<object> _Collection; public int Level { get; set; } public T Item { get; set; } public List<U> Items { get; private set; } public bool IsExpand { get { return _IsExpand; } set { if (_IsExpand != value) { _IsExpand = value; OnPropertyChanged("IsExpand"); if (value) { OnExpand(); } else { OnShrink(); } } } } private bool _IsExpand; public abstract bool CanExpand { get; } protected abstract void OnExpand(); protected abstract void OnShrink(); #region INotifyPropertyChanged メンバ public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } #endregion } class FlatItem : FratWrapperItem<TestValue, FlatItem> { public static FlatItem Create(TestValue item) { FlatItem root = new FlatItem(0, item, new ObservableCollection<object>()); root.Collection.Add(root); return root; } public FlatItem(int level, TestValue item, ObservableCollection<object> collection) : base(level,item,collection){} protected override void OnExpand() { int index = Collection.IndexOf(this) ; foreach (TestValue child in this.Item.Items) { FlatItem childFlat = new FlatItem(this.Level+1 ,child, Collection); Collection.Insert(++index, childFlat); this.Items.Add(childFlat); } } protected override void OnShrink() { foreach (FlatItem flatChild in this.Items) { flatChild.IsExpand = false; Collection.Remove(flatChild ); } } public override bool CanExpand { get { return this.Item.Items.Count > 0; } } } public class LevelMarginConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double span = 20; if (parameter != null) { double.TryParse(parameter.ToString(),out span); } return new Thickness((int)value * span, 0, 0, 0); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); }
#編集したらコードが壊れたので再投稿個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
すべての返信
-
Bのように表示するだけなら左にマージンと展開用のボタンを付けるだけですけどね。
<ItemsControl ItemsSource="{Binding Collection}" > <ItemsControl.Resources> <app:LevelMarginConverter x:Key="conv" xmlns:app="clr-namespace:WpfApplication1"/> </ItemsControl.Resources> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Vertical" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Margin="{Binding Path=Level,Converter={StaticResource conv},ConverterParameter=10}"> <ToggleButton IsChecked="{Binding Path=IsExpand}" x:Name="tgl" Width="10" Height="10" IsEnabled="{Binding Path=CanExpand}" > </ToggleButton> <TextBlock Text="{Binding Item.Value}" /> </StackPanel> <DataTemplate.Triggers> <DataTrigger Binding="{Binding CanExpand}" Value="false" > <Setter TargetName="tgl" Property="Visibility" Value="Hidden" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
public partial class Window1 : Window { public Window1() { InitializeComponent(); var flat = FlatItem.Create(TestValue.CreateTestData()); this.DataContext = flat; } } class TestValue { public TestValue() { Items = new List<TestValue>(); } public string Value { get; set; } public List<TestValue> Items { get; private set; } public static TestValue CreateTestData() { TestValue lv0 = new TestValue(); lv0.Value = "ルート"; for (int i = 1; i <= 5; i++) { TestValue lv1 = new TestValue(); lv1.Value = i.ToString(); for (int j = 1; j <= 2; j++) { TestValue lv2 = new TestValue(); lv2.Value = lv1.Value + "." + j.ToString(); for (int k = 1; k <= 10; k++) { TestValue lv3 = new TestValue(); lv3.Value = lv2.Value + "." + k.ToString(); lv2.Items.Add(lv3); } lv1.Items.Add(lv2); } lv0.Items.Add(lv1); } return lv0; } } abstract class FratWrapperItem<T,U> : INotifyPropertyChanged { public FratWrapperItem(int level , T item, ObservableCollection<object> collection) { this.Items = new List<U>(); this.Level = level; this.Item = item; this._Collection = collection; } public ObservableCollection<object> Collection { get { return _Collection; } } private ObservableCollection<object> _Collection; public int Level { get; set; } public T Item { get; set; } public List<U> Items { get; private set; } public bool IsExpand { get { return _IsExpand; } set { if (_IsExpand != value) { _IsExpand = value; OnPropertyChanged("IsExpand"); if (value) { OnExpand(); } else { OnShrink(); } } } } private bool _IsExpand; public abstract bool CanExpand { get; } protected abstract void OnExpand(); protected abstract void OnShrink(); #region INotifyPropertyChanged メンバ public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } #endregion } class FlatItem : FratWrapperItem<TestValue, FlatItem> { public static FlatItem Create(TestValue item) { FlatItem root = new FlatItem(0, item, new ObservableCollection<object>()); root.Collection.Add(root); return root; } public FlatItem(int level, TestValue item, ObservableCollection<object> collection) : base(level,item,collection){} protected override void OnExpand() { int index = Collection.IndexOf(this) ; foreach (TestValue child in this.Item.Items) { FlatItem childFlat = new FlatItem(this.Level+1 ,child, Collection); Collection.Insert(++index, childFlat); this.Items.Add(childFlat); } } protected override void OnShrink() { foreach (FlatItem flatChild in this.Items) { flatChild.IsExpand = false; Collection.Remove(flatChild ); } } public override bool CanExpand { get { return this.Item.Items.Count > 0; } } } public class LevelMarginConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double span = 20; if (parameter != null) { double.TryParse(parameter.ToString(),out span); } return new Thickness((int)value * span, 0, 0, 0); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); }
#編集したらコードが壊れたので再投稿個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)