如何根据子对象调整画布大小<;wpf>;

如何根据子对象调整画布大小<;wpf>;,wpf,canvas,Wpf,Canvas,我写 <TabItem Header="Map"> <Grid Background="#FFE5E5E5" Margin="0,0,0,0"> <ScrollViewer x:Name="mapScroll" HorizontalAlignment="Left" Height="248" Margin="10,10,0,0" VerticalAlignment="Top" Width="467" HorizontalScrollBarVis

我写

 <TabItem Header="Map">
     <Grid Background="#FFE5E5E5" Margin="0,0,0,0">
      <ScrollViewer x:Name="mapScroll" HorizontalAlignment="Left" Height="248" Margin="10,10,0,0" VerticalAlignment="Top" Width="467" HorizontalScrollBarVisibility="Auto"/>
     </Grid>
    </TabItem>

 Button btnTest1 = new Button();
     btnTest1.Width = 100;
     btnTest1.Height = 150;
     Canvas.SetLeft(btnTest1, 200);
     Canvas.SetTop(btnTest1, 200);
ca.Children.Add(btnTest1);
按钮位于画布的边界区域。 按钮的侧面不可见,滚动条未激活。 我想调整画布大小,以包括完整的按钮,所以滚动条应该被激活。。。 ScollViewer的大小相同


如何调整画布的大小,以便滚动条必须激活。

我假设大量的代码会让大多数人望而却步,所以我在开始时发布解决方案。 我的概念是使画布的高度取决于Canvas.Children.Count。这将在每次集合更改时更改画布的高度。但不幸的是,Children.Count不是依赖属性,因此它不反映任何更改。我使用ChildrenCount属性实现了自定义画布,它让用户了解更改。另一个问题是Canvas不提供任何事件来将项添加到其子项,所以我被要求从基类重写OnVisualChildrenChanged事件。我指望你能理解这么多代码

public class CustomCanvas : Canvas, INotifyPropertyChanged
{
    private int childrenCount;

    public int ChildrenCount
    {
        get { return childrenCount; }
        set
        {
            childrenCount = value;
            OnPropertyChanged();
        }
    }

    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        if (visualAdded == null)
            --ChildrenCount;
        else
            ++ChildrenCount;
        base.OnVisualChildrenChanged(visualAdded, visualRemoved);
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
XAML:


public类ChildrenCountToHeightConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,System.Globalization.CultureInfo区域性)
{
var childrenNumber=System.Convert.ToInt32(值[0].ToString());
if(childrenNumber==0)
返回0;
var children=(UIElementCollection)值[1];
var y=children.OfType().Max(x=>Canvas.GetTop(x));
返回y+children.OfType().First(x=>Canvas.GetTop(x)==y)。高度+50;
}
公共对象[]转换回(对象值,类型[]目标类型,对象参数,System.Globalization.CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}

我确信它需要一些改变,但现在它起作用了。添加按钮后,画布的高度将根据底部的按钮进行调整。

可能与“谢谢”重复。这段代码运行得很好。但我必须添加图像和文本块,所以我更改了“children.OfType()”->“children.OfType()”,并将图像添加到CustomCanvas boundary like按钮中(暂时仅添加图像),然后就不起作用了。如何适应图像和文本块?我想不仅适应垂直对齐,还适应水平对齐。如果您想要许多不同类型的对象,只需添加其基本类,如FrameworkElement,而不是Image或Button。如果您想要宽度,您需要添加与高度相同的绑定,但需要添加另一个转换器,您将在其中查找Canvas.GetLeft(obj)。如果有用,请将其标记为answear。
public class CustomCanvas : Canvas, INotifyPropertyChanged
{
    private int childrenCount;

    public int ChildrenCount
    {
        get { return childrenCount; }
        set
        {
            childrenCount = value;
            OnPropertyChanged();
        }
    }

    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        if (visualAdded == null)
            --ChildrenCount;
        else
            ++ChildrenCount;
        base.OnVisualChildrenChanged(visualAdded, visualRemoved);
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
 <StackPanel>
    <StackPanel.Resources>
        <local:ChildrenCountToHeightConverter x:Key="ChildrenCountToHeightConverter"/>
    </StackPanel.Resources>
    <ScrollViewer HorizontalAlignment="Left" Height="248" Margin="10,10,0,0" VerticalAlignment="Top" Width="467"
                  HorizontalScrollBarVisibility="Auto"
          VerticalScrollBarVisibility="Auto">
        <local:CustomCanvas x:Name="CustomCanvas" MaxHeight="1555">
            <local:CustomCanvas.Height>
                <MultiBinding Converter="{StaticResource ChildrenCountToHeightConverter}">
                    <Binding RelativeSource="{RelativeSource Self}" Path="(local:CustomCanvas.ChildrenCount)"/>
                    <Binding RelativeSource="{RelativeSource Self}" Path="(local:CustomCanvas.Children)"/>
                </MultiBinding>
            </local:CustomCanvas.Height>
        </local:CustomCanvas>
    </ScrollViewer>
    <Button Content="dodaj" Click="ButtonBase_OnClick"/>
</StackPanel>
 private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        Button btnTest1 = new Button();
        btnTest1.Width = 100;
        btnTest1.Height = 150;
        Canvas.SetLeft(btnTest1, 200);
        Canvas.SetTop(btnTest1, 200);
        CustomCanvas.Children.Add(btnTest1);
    }
public class ChildrenCountToHeightConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var childrenNumber = System.Convert.ToInt32(values[0].ToString());
        if (childrenNumber == 0)
            return 0;
        var children = (UIElementCollection)values[1];
        var y = children.OfType<Button>().Max(x => Canvas.GetTop(x));
        return y + children.OfType<Button>().First(x => Canvas.GetTop(x) == y).Height + 50;
    }

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