C# WPF自定义框架元素/IScrollInfo

C# WPF自定义框架元素/IScrollInfo,c#,wpf,xaml,wpf-controls,frameworkelement,C#,Wpf,Xaml,Wpf Controls,Frameworkelement,我有一个简单的测试应用程序,它有一个基本的自定义FrameworkElement实现(TestElement如下)。TestElement创建了两个图形视觉效果,并在构造函数中绘制了一些宽度为600的内容。它还实现了IScrollinfo的必要位;包含元素的窗口有一个scrollviewer,最大大小为300x300。此时会出现滚动条,但不会滚动TestElement的内容 有人能告诉我我想做的事是否可能,如果可能,我做错了什么吗。我可以在SetHorizontalOffset中重新渲染图形视觉

我有一个简单的测试应用程序,它有一个基本的自定义
FrameworkElement
实现(TestElement如下)。TestElement创建了两个图形视觉效果,并在构造函数中绘制了一些宽度为600的内容。它还实现了IScrollinfo的必要位;包含元素的窗口有一个scrollviewer,最大大小为300x300。此时会出现滚动条,但不会滚动TestElement的内容

有人能告诉我我想做的事是否可能,如果可能,我做错了什么吗。我可以在SetHorizontalOffset中重新渲染图形视觉效果,但出于性能原因,我不想这样做,因为我已经绘制了所有需要的图形

我希望这个问题有点道理——如果没有,请告诉我,我可以澄清

非常感谢-卡尔

public class TestElement : FrameworkElement, IScrollInfo
{
    DrawingVisual visual;
    DrawingVisual visual2;
    public TestElement()
    {
        Draw();
        this.MaxWidth = 600;
        this.MaxHeight = 300;
    }
    public void Draw()
    {
        if(visual == null)
        {
            visual = new DrawingVisual();
            base.AddVisualChild(visual);
            base.AddLogicalChild(visual);
        }
        if (visual2 == null)
        {
            visual2 = new DrawingVisual();
            base.AddVisualChild(visual2);
            base.AddLogicalChild(visual2);
        }
        Random rand = new Random();
        var pen = new Pen(Brushes.Black, 1);
        using(var dc = visual.RenderOpen())
        {
            for (int i = 0; i < 400; i++) 
            {
                var r = rand.Next(10, 200);
                dc.DrawLine(pen, new Point(i, r), new Point(i, 0));
            }
        }
        using (var dc = visual2.RenderOpen())
        {
            for (int i = 0; i < 200; i++)
            {
                var r = rand.Next(10, 200);
                dc.DrawLine(pen, new Point(i, r), new Point(i, 0));
            }
            visual2.Offset = new Vector(400, 0);
        }
    }
    protected override int VisualChildrenCount 
    {
        get { return 2; }
    }
    protected override Visual GetVisualChild(int index)
    {
        return index == 0 ? visual : visual2;
    }
    protected override Size MeasureOverride(Size availableSize)
    {
        viewport = availableSize;
        owner.InvalidateScrollInfo();
        return base.MeasureOverride(availableSize);
    }
    protected override Size ArrangeOverride(Size finalSize)
    {
        var value = base.ArrangeOverride(finalSize);
        return base.ArrangeOverride(finalSize);
    }


    Point offset = new Point(0,0);
    public void SetHorizontalOffset(double offset)
    {
        this.offset.X = offset;
        this.InvalidateArrange();
    }

    public void SetVerticalOffset(double offset)
    {
        this.offset.Y = offset;
    }

    public Rect MakeVisible(Visual visual, Rect rectangle)
    {
        throw new NotImplementedException();
    }

    public bool CanVerticallyScroll { get; set; }
    public bool CanHorizontallyScroll { get; set; }

    Size extent = new Size(600, 300);

    private Size viewport = new Size(0, 0);
    public double ExtentWidth
    {
        get { return extent.Width; }
    }

    public double ExtentHeight
    {
        get {return extent.Height; }
    }

    public double ViewportWidth
    {
        get { return viewport.Width; }
    }

    public double ViewportHeight
    {
        get { return viewport.Height; }
    }

    public double HorizontalOffset
    {
        get { return offset.X; }
    }

    public double VerticalOffset
    {
        get { return offset.Y; }
    }

    private ScrollViewer owner;

    public ScrollViewer ScrollOwner
    {
        get { return owner; }
        set { owner = value; }
    }


}
public类TestElement:FrameworkElement,IScrollInfo
{
绘画视觉;
绘制视觉2;
公共测试元素()
{
Draw();
此参数为.MaxWidth=600;
此参数为.MaxHeight=300;
}
公众抽签()
{
如果(可视==null)
{
visual=新绘图visual();
base.AddVisualChild(可视);
base.AddLogicalChild(可视);
}
如果(visual2==null)
{
visual2=新绘图VISUAL();
base.AddVisualChild(visual2);
base.AddLogicalChild(visual2);
}
Random rand=新的Random();
var笔=新笔(刷子。黑色,1);
使用(var dc=visual.RenderOpen())
{
对于(int i=0;i<400;i++)
{
var r=兰德下一步(10200);
直流拉线(笔,新点(i,r),新点(i,0));
}
}
使用(var dc=visual2.RenderOpen())
{
对于(int i=0;i<200;i++)
{
var r=兰德下一步(10200);
直流拉线(笔,新点(i,r),新点(i,0));
}
visual2.偏移量=新向量(400,0);
}
}
受保护的重写int VisualChildrenCount
{
获取{return 2;}
}
受保护的重写Visual GetVisualChild(int索引)
{
返回索引==0?可视:可视2;
}
受保护的覆盖尺寸测量覆盖(尺寸可用尺寸)
{
viewport=availableSize;
owner.InvalidateScrollInfo();
返回基准。测量超越(可用尺寸);
}
受保护的替代尺寸排列替代(尺寸最终化)
{
var值=基本排列覆盖(最终化);
返回基数。安排覆盖(最终化);
}
点偏移=新点(0,0);
公共void SetHorizontalOffset(双偏移)
{
此.offset.X=偏移量;
this.InvalidateArrange();
}
公共无效设置垂直偏移(双偏移)
{
此.offset.Y=偏移量;
}
公共矩形使可见(可视,矩形)
{
抛出新的NotImplementedException();
}
公共布尔CanVerticallyScroll{get;set;}
公共布尔值可水平滚动{get;set;}
尺寸范围=新尺寸(600300);
私有大小视口=新大小(0,0);
公共双延长线
{
获取{返回范围.Width;}
}
公共双延伸灯
{
获取{返回范围.高度;}
}
公共双视口宽度
{
获取{return viewport.Width;}
}
公共双视口高度
{
获取{return viewport.Height;}
}
公共双水平偏移
{
获取{return offset.X;}
}
公共双垂直偏移
{
获取{return offset.Y;}
}
私有滚动浏览者所有者;
公共滚动查看器滚动所有者
{
获取{返回所有者;}
设置{owner=value;}
}
}
xaml:

<Window x:Class="TestWpfApp.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l ="clr-namespace:TestWpfApp"
Title="TestWpfApp" Height="300" Width="300" >
<Grid>
    <ScrollViewer CanContentScroll="True" HorizontalScrollBarVisibility="Visible">
        <l:TestElement CanHorizontallyScroll="True" />
    </ScrollViewer>
</Grid>


刚刚喝了一杯啤酒,这有助于找到解决方案

这不是最终的“做得很好”解决方案,但可以肯定,它将进一步帮助您:

排列覆盖的实现中,请尝试:

protected override Size ArrangeOverride(Size finalSize)
{
    this.visual.Offset = new Vector(-this.HorizontalOffset, -this.VerticalOffset);

    var value = base.ArrangeOverride(finalSize);
    return base.ArrangeOverride(finalSize);
}
基本上你必须自己移动你的物体

有关更多信息,请参阅本文: .
通常,您必须使用转换将对象移动到滚动对象的位置。

Hi-谢谢您的回复。是的,这是可行的(我确实尝试过类似的方法,但由于某些原因我无法让它发挥作用),但我同意这不是一个“做得好”的解决方案。此外,我将不得不做一个抵消簿记公平位,因为我需要这将有多个图形视觉所有不同的偏移量。我会给它一点时间,看看是否有什么补充,然后我会接受这个解决方案。