在条形图中自动执行矩形的ScaleTransform

我有UserControl的条形图:

<UserControl ... Name="uc">

    <Grid>
        <Canvas>
            <Canvas.Resources>
                <Style TargetType="Line">
                    <Setter Property="X1" Value="0"/>
                    <Setter Property="X2" Value="{Binding actualWidth,ElementName=uc}"/>
                    <Setter Property="StrokeThickness" Value="1"/>
                </Style>
                <Style TargetType="TextBlock">
                    <Setter Property="Canvas.Right" Value="0"/>
                </Style>
            </Canvas.Resources>

            <Line Y1="{Binding HighestPoint}" Y2="{Binding HighestPoint}" 
                  Canvas.Bottom="{Binding HighestPoint}"
                  Stroke="Red"/>
            <TextBlock Text="{Binding HighestPoint,StringFormat=N0}" 
                       Canvas.Bottom="{Binding HighestPoint}"/>

            <Line Y1="{Binding SecondPoint}" Y2="{Binding SecondPoint}" Stroke="Blue" 
                  Canvas.Bottom="{Binding SecondPoint}"/>
            <TextBlock Text="{Binding SecondPoint,StringFormat=N0}" 
                       Canvas.Bottom="{Binding SecondPoint}"/>

            <Line Y1="{Binding FirstPoint}" Y2="{Binding FirstPoint}" Stroke="Green" 
                  Canvas.Bottom="{Binding FirstPoint}"/>
            <TextBlock Text="{Binding FirstPoint,StringFormat=N0}" 
                       Canvas.Bottom="{Binding FirstPoint}"/>
        </Canvas>

        <ItemsControl ScrollViewer.CanContentScroll="True"
                      ItemsSource="{Binding RectCollection}"
                      Margin="0 0 20 0">

            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle Width="20" Height="{Binding}"
                               Margin="0 0 2 0" 
                               VerticalAlignment="Bottom"
                               Opacity=".5" Fill="Green"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

            <ItemsControl.Template>
                <ControlTemplate>
                    <ScrollViewer
                     VerticalScrollBarVisibility="Hidden"
                     Background="{TemplateBinding Panel.Background}">
                        <ItemsPresenter snapsToDevicePixels="{TemplateBinding snapsToDevicePixels}"/>
                    </ScrollViewer>
                </ControlTemplate>
            </ItemsControl.Template>

            <ItemsControl.ItemsPanel>
                <itemspaneltemplate>
                    <VirtualizingStackPanel Orientation="Horizontal"/>
                </itemspaneltemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>

    </Grid>
</UserControl>

在我的MainWindow中,我在Grid.Row中使用了它,它通常看起来像这样:

在条形图中自动执行矩形的ScaleTransform

ICommand事件的SizeChanged中重新计算了这些行顶部的值。当我调整窗口大小时,它变成这样:

在条形图中自动执行矩形的ScaleTransform

矩形的高度不会自动更改!我可以重新计算该double中每个矩形的高度,即ICommand,以重新调整效率不高的BUT,对吧?有没有简单的方法可以一次转换所有这些矩形?

编辑

我还要在Canvas中进行一些更改,以使其正常运行。这是我现在UserControl所拥有的:

<UserControl .." Name="uc">

    <UserControl.Resources>
        <local:MyConverter x:Key="converter"/>
    </UserControl.Resources>

    <Grid VerticalAlignment="Bottom">
        <Canvas>
            <Canvas.Resources>
                <Style TargetType="Line">
                    <Setter Property="X1" Value="0"/>
                    <Setter Property="X2" Value="{Binding actualWidth,ElementName=uc}"/>
                    <Setter Property="StrokeThickness" Value="1"/>
                </Style>
                <Style TargetType="TextBlock">
                    <Setter Property="Canvas.Right" Value="0"/>
                </Style>
            </Canvas.Resources>

            <Line Y1="135" Y2="135" Canvas.Bottom="135" Stroke="Red"/>
            <TextBlock Text="{Binding HighestPoint,StringFormat=N0}" Canvas.Bottom="135"/>
            <Line Y1="90" Y2="90" Stroke="Blue" Canvas.Bottom="90"/>
            <TextBlock Text="{Binding SecondPoint,StringFormat=N0}" Canvas.Bottom="90"/>
            <Line Y1="45" Y2="45" Stroke="Green" Canvas.Bottom="45"/>
            <TextBlock Text="{Binding FirstPoint,StringFormat=N0}" Canvas.Bottom="45"/>
        </Canvas>

        <ItemsControl ScrollViewer.CanContentScroll="True"
                      Height="135"
                      ItemsSource="{Binding RectCollection}"
                      Margin="0 0 20 0">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Rectangle Width="20" 
                            Margin="0 0 2 0" 
                            VerticalAlignment="Bottom"
                            Opacity=".5" Fill="Green">
                            <Rectangle.Height>
                                <MultiBinding Converter="{StaticResource converter}">
                                    <Binding Path="actualHeight"
                                             RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
                                    <Binding Path="DataContext.HighestPoint"
                                             RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
                                    <Binding />
                                </MultiBinding>
                            </Rectangle.Height>
                        </Rectangle>
                        <TextBlock Text="{Binding StringFormat=N2}" 
                            Margin="0 0 0 20">
                            <TextBlock.LayoutTransform>
                                <RotateTransform Angle="-90"/>
                            </TextBlock.LayoutTransform>
                        </TextBlock>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

            <ItemsControl.Template>
                <ControlTemplate>
                    <ScrollViewer
                     VerticalScrollBarVisibility="Hidden"
                     Background="{TemplateBinding Panel.Background}">
                        <ItemsPresenter snapsToDevicePixels="{TemplateBinding snapsToDevicePixels}"/>
                    </ScrollViewer>
                </ControlTemplate>
            </ItemsControl.Template>

            <ItemsControl.ItemsPanel>
                <itemspaneltemplate>
                    <VirtualizingStackPanel Orientation="Horizontal"/>
                </itemspaneltemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
</UserControl>

MainWindow中,我有这些:

<Window ...>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandaction Command="{Binding SizeChanged}"
                                   commandparameter="{Binding ElementName=uc}"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="SizeChanged">
            <i:InvokeCommandaction Command="{Binding SizeChanged}"
                                   commandparameter="{Binding ElementName=uc}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

    <Window.DataContext>
        <local:VM/>
    </Window.DataContext>

    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <local:TestControl Grid.Row="1" x:Name="uc"/>
        <Button Grid.Row="2" Content="Add" Margin="50" Command="{Binding Add}"/>
    </Grid>
</Window>

和ViewModel中的这些是添加矩形并设置范围的相关函数:

public VM()
{
    Add = new Command(AddRect,(o) => true);
    SizeChanged = new Command(sizeChanged,(o) => true);
}

void sizeChanged(object obj)
{
    var c = obj as TestControl;
    CalculateLineText(c.actualHeight);
}

void AddRect(object obj)
{
    var value = rand.NextDouble() * 500;
    if (max < value) CalculateLineText(value);
    RectCollection.Insert(0,value);
}

void CalculateLineText(double d)
{
    max = d;
    HighestPoint = Math.Round(d);
    FirstPoint = Math.Round(d / 3);
    SecondPoint = Math.Round(d / 3 * 2);
}

和值转换器中的

public class MyConverter : IMultiValueConverter
{
    public object Convert(object[] values,Type targetType,object parameter,CultureInfo culture)
    {
        var height = (double)values[0];
        var highest = (double)values[1];
        var value = (double)values[2];
        return value * height / highest;
    }

    public object[] ConvertBack(object value,Type[] targetTypes,CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

调整窗口大小时仍然存在一个小问题,这可能是因为我已经硬编码了ItemsControl的高度。

编辑

此:

void CalculateLineText(double d)
{
    if (max < d) max = d;
    HighestPoint = Math.Round(max);
    FirstPoint = Math.Round(max / 3);
    SecondPoint = Math.Round(max / 3 * 2);
}

解决了调整大小的问题。

b_bunny 回答:在条形图中自动执行矩形的ScaleTransform

作为我对other question的回答的扩展,当值范围为0..1时,可以将ItemsControl的ActualHeight用作比例因子:

<ItemsControl ItemsSource="{Binding}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid Width="20" Margin="2">
                <Rectangle VerticalAlignment="Bottom"
                           Height="{Binding}" Fill="LightGray">
                    <Rectangle.LayoutTransform>
                        <ScaleTransform ScaleY="{Binding ActualHeight,RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
                    </Rectangle.LayoutTransform>
                </Rectangle>
                <TextBlock Text="{Binding StringFormat={}{0:N2}}">
                    <TextBlock.LayoutTransform>
                        <RotateTransform Angle="-90"/>
                    </TextBlock.LayoutTransform>
                </TextBlock>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

此代码位于后面的代码中:

Random r = new Random();
DataContext = Enumerable.Range(0,20).Select(i => r.NextDouble());

编辑:除了ScaleTransform之外,您还可以对矩形的Height属性使用MultiBinding。以下示例假定,除了Values集合外,视图模型中还具有Range属性,例如像这样:

Random r = new Random();

DataContext = new
{
    Range = 100d,Values = Enumerable.Range(0,20).Select(i => r.NextDouble() * 100)
};

然后XAML将如下所示:

<ItemsControl ItemsSource="{Binding Values}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid Width="20" Margin="2">
                <Rectangle VerticalAlignment="Bottom" Fill="LightGray">
                    <Rectangle.Height>
                        <MultiBinding Converter="{StaticResource HeightConverter}">
                            <Binding Path="ActualHeight"
                                     RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
                            <Binding Path="DataContext.Range"
                                     RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
                            <Binding Path="."/>
                        </MultiBinding>
                    </Rectangle.Height>
                </Rectangle>
                <TextBlock Text="{Binding StringFormat={}{0:N2}}">
                    <TextBlock.LayoutTransform>
                        <RotateTransform Angle="-90"/>
                    </TextBlock.LayoutTransform>
                </TextBlock>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

使用此IValueConverter:

public class HeightConverter : IMultiValueConverter
{
    public object Convert(object[] values,Type targetType,object parameter,CultureInfo culture)
    {
        return (double)values[0] / (double)values[1] * (double)values[2];
    }

    public object[] ConvertBack(object value,Type[] targetTypes,CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
本文链接:https://www.f2er.com/2957411.html

大家都在问