ListBoxで棒グラフ…ちょっと何言ってるか分からないですね…
MultiBingingを使って
ListBoxの幅に合わせて要素の幅を変更している
上半分のListBoxは失敗例で
下半分が期待通りにできたListBox
Bindingソース1 ListBoxのActualWidth
Bindingソース2 DataContext、ここでは0.5とか0.8
Bindingターゲット ListBoxの要素のWidth
<Window xClass="_20190321_ListBoxで棒グラフ_比率で伸縮.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlnslocal="clr-namespace:_20190321_ListBoxで棒グラフ_比率で伸縮"
mcIgnorable="d"
Title="MainWindow" Height="300" Width="400">
<WindowResources>
<localMyConverter xKey="myConv"/>
<localMyMultiConverter xKey="myMultiConv"/>
</WindowResources>
<Grid>
<StackPanel>
<ListBox Name="MyListBox1" ItemsSource="{Binding}">
<ListBoxItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"/>
<Border Background="MediumOrchid" Height="10"
Width="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBoxItemTemplate>
</ListBox>
<ListBox Name="MyListBox2" ItemsSource="{Binding}">
<ListBoxItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"/>
<Border Background="MediumAquamarine" Height="10">
<BorderWidth>
<MultiBinding Converter="{StaticResource myMultiConv}">
<Binding ElementName="MyListBox2" Path="ActualWidth"/>
<Binding/>
</MultiBinding>
</BorderWidth>
</Border>
</StackPanel>
</DataTemplate>
</ListBoxItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace _20190321_ListBoxで棒グラフ_比率で伸縮
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ContentRendered += MainWindow_ContentRendered;
}
private void MainWindow_ContentRendered(object sender, EventArgs e)
{
List<double> myData = new List<double> { 0.5, 0.8, 0.3, 1.0 };
DataContext = myData;
}
}
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double width = (double)parameter;
double rate = (double)value;
return (width * rate) - 20;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class MyMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double width = (double)values[0];
double rate = (double)values[1];
return (width - 16) * rate;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
棒グラフはListBoxのItemTemplateに設定したBorderを使って表現
そのBorderのWidthにMultiBindingを使っている
失敗例
ConverterのConverterParameterにListboxのActualWidthを使おうとしているのが
25、26行目なんだけど
これはエラーになる
ConverterParameterにDependencyProperty以外を使っているのが良くないみたい、だけどどうすればいいのかわからん
よくなさそうなところ
"ConverterParameter={Binding RelativeSource"
でぐぐったら
実際に使うときはこんな感じ
<Window xClass="_20190321_Listboxで棒グラフ2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlnsx="http://schemas.microsoft.com/winfx/2006/xaml"
xmlnsd="http://schemas.microsoft.com/expression/blend/2008"
xmlnsmc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlnslocal="clr-namespace:_20190321_Listboxで棒グラフ2"
mcIgnorable="d"
Title="MainWindow" Height="200" Width="400">
<WindowResources>
<localMyMultiConverter xKey="myMultiConv"/>
</WindowResources>
<Grid>
<StackPanel>
<ListBox Name="MyListBox" ItemsSource="{Binding}">
<ListBoxItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Value}"/>
<Border Background="MediumOrchid" Height="10" HorizontalAlignment="Left">
<BorderWidth>
<MultiBinding Converter="{StaticResource myMultiConv}">
<Binding ElementName="MyListBox" Path="ActualWidth"/>
<Binding Path="Rate"/>
</MultiBinding>
</BorderWidth>
</Border>
</StackPanel>
</DataTemplate>
</ListBoxItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Window>
これはさっきのと基本は変わりなし
BorderのHorizontalAlignmentにleftを指定したのと
18行目、BindingのPathに数値表示のTextBlockに
Valueと
23行目、BorderのPathにRateを指定、これは幅の割合
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
namespace _20190321_Listboxで棒グラフ2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ContentRendered += MainWindow_ContentRendered;
}
private void MainWindow_ContentRendered(object sender, EventArgs e)
{
List<double> dList = new List<double>() { 1100, 2340, 330, 5328 };
double max = dList.Max();
List<MyData> myDatas = new List<MyData>();
foreach (var item in dList)
{
myDatas.Add(new MyData(item, max));
}
DataContext = myDatas;
}
}
public class MyMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double width = (double)values[0];
double rate = (double)values[1];
return (width - 16) * rate;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class MyData
{
public double Value { get; set; }
public double Rate { get; set; }
public MyData(double value, double max)
{
Value = value;
Rate = value / max;
}
}
}
データ
バインディングに使う値を実際の値と、表示幅割合指定用の値、この2つに分けた
実行すると
伸ばす
いいねえ
縮めると
これは
Converterの45行目で幅を-20しているから
じゃあなくせばいいかとすると
最大幅になる要素がListBoxと同じ幅になって、常にスクロールバーが表示されてしまう
これは最大でもListBox幅の0.99倍とかにするか、最低幅を1にすればいいかも
最後に-20するんじゃなくて元の幅から-16程度したものの割合にすれば
50行目をやめて51行目
割合が0.0にならない限り0にはならないから
当たり前なんだよなあ、うっかり
でもこれで
ここまでできてみれば難しくないんだけど、最初はGrid.ColumnDefinitionsでなんとかしようとしたり遠回りしてた
あとは
WPFにもグラフ表示するコン
トロールもあったはずで、それを使ったほうが速いかもしれないけど、最近ListBoxばかり使っていたからListBoxから離れられなかったw
ギットハブ
今回のアプリのダウンロード先
関連記事
2019/3/5は16日前
ListBox.ItemTemplateを使って要素の表示を変更