如何在不执行措施或安排通行证的情况下手动告诉所有者的WPF控件刷新/重新刷新?

StackOverflow https://stackoverflow.com/questions/7801680

我们正在控制子类的自定义绘图 OnRender. 。此图形代码基于外部触发器和数据。因此,每当触发触发时,我们都需要根据该数据重新渲染控件。我们正在尝试做的是找出如何强制控制重新渲染,但没有通过整个布局通行证。

如上所述,我看到的大多数答案围绕着无效 Visual 这使布局无效,迫使新的措施和安排非常昂贵的措施,尤其是对于非常复杂的视觉树木。但是再次,布局确实 不是 更改,视觉树也没有。唯一做的是外部数据,其呈现方式不同。因此,这严格来说是一个纯粹的渲染问题。

同样,我们只是在寻找一种简单的方法来告诉控制它需要重新执行 OnRender. 。我已经看到了一个“黑客”,您可以创建一个新的 DependencyProperty 并在要刷新控件时将其注册为“ altimentsrender”,您只是将其设置为一定的值,但是我对这些属性的默认实现中发生的事情更感兴趣:他们所说的影响该行为。


更新:

好吧,看来没有任何这样的电话 AffectsRender 标志仍然会导致内部安排通过(根据下面的编码答案),但我发布了第二个答案,显示内置行为以及工作措施,以抑制您的布局通过,从运行中的简单nullable大小为一只旗。见下文。

有帮助吗?

解决方案 2

好的,我正在回答这个问题,以向人们展示为什么Codenaked的答案正确,但是如果可以的话,请使用星号,并提供工作能力。但是,在良好的所谓统计中,我仍然将他的回答标记为他的回答,因为他的回答将我带到了这里。

更新:从那以后,我将接受的答案移至此处,原因有两个。一个,我希望人们知道那里 一个解决方案(大多数人只阅读被接受的答案并继续前进)和两个,考虑到他的代表为25K,我认为他不介意我是否把它拿回来! :)

这就是我所做的。为了测试这一点,我创建了这个子类...

public class TestPanel : DockPanel
{
    protected override Size MeasureOverride(Size constraint)
    {
        System.Console.WriteLine("MeasureOverride called for " + this.Name + ".");
        return base.MeasureOverride(constraint);
    }

    protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
    {
        System.Console.WriteLine("ArrangeOverride called for " + this.Name + ".");
        return base.ArrangeOverride(arrangeSize);
    }

    protected override void OnRender(System.Windows.Media.DrawingContext dc)
    {
        System.Console.WriteLine("OnRender called for " + this.Name + ".");
        base.OnRender(dc);
    }

}

...我这样布置了(请注意它们是嵌套的):

<l:TestPanel x:Name="MainTestPanel" Background="Yellow">

    <Button Content="Test" Click="Button_Click" DockPanel.Dock="Top" HorizontalAlignment="Left" />

    <l:TestPanel x:Name="InnerPanel" Background="Red" Margin="16" />

</l:TestPanel>

当我调整窗户大小时,我得到了这个...

MeasureOverride called for MainTestPanel.
MeasureOverride called for InnerPanel.
ArrangeOverride called for MainTestPanel.
ArrangeOverride called for InnerPanel.
OnRender called for InnerPanel.
OnRender called for MainTestPanel.

但是当我打电话 InvalidateVisual 在“维护策略”(在按钮的“单击”事件中),我得到了...

ArrangeOverride called for MainTestPanel.
OnRender called for MainTestPanel.

请注意,如何调用任何测量替代,并且仅调用外部控制的安装螺旋体。

它并不完美,好像您的内部计算很重 ArrangeOverride 在您的子类(不幸的是我们这样做)中,仍然被执行,但至少孩子们并没有落入同一命运。

但是,如果您不知道一个儿童控件具有带有AffectParentArnge位设置的属性(再次,我们这样做),则可以更好地使用一个可取的属性 Size 作为抑制从重新进入的依据逻辑的标志,除非在需要时,例如...

public class TestPanel : DockPanel
{
    Size? arrangeResult;

    protected override Size MeasureOverride(Size constraint)
    {
        arrangeResult = null;
        System.Console.WriteLine("MeasureOverride called for " + this.Name + ".");
        return base.MeasureOverride(constraint);
    }

    protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
    {
        if(!arrangeResult.HasValue)
        {
            System.Console.WriteLine("ArrangeOverride called for " + this.Name + ".");
            // Do your arrange work here
            arrangeResult = base.ArrangeOverride(arrangeSize);
        }

        return arrangeResult.Value;
    }

    protected override void OnRender(System.Windows.Media.DrawingContext dc)
    {
        System.Console.WriteLine("OnRender called for " + this.Name + ".");
        base.OnRender(dc);
    }

}

现在,除非有特定的东西需要重新执行安排逻辑(作为对MeatureOverride的调用),您才会获得启用,如果您想明确强制迫使安排逻辑,只需取消尺寸,请拨打无效,呼叫无效,鲍勃是您的叔叔! :)

希望这可以帮助!

其他提示

不幸的是,你必须打电话 无效的案件, ,打电话 无效 内部。这 OnRender 方法称为安排阶段的一部分,因此您需要告诉WPF重新排列控件(InvalidAtateArrange所做的),并且需要重新绘制(无效的ViSual Viesual)。

FrameworkPropertyMetadata.AffectsRender 选项只需告诉WPF打电话 InvalidateVisual 当关联的属性更改时。

如果您有一个控件(我们调用此主控制器),该控件覆盖了覆盖物并包含几个后代控件,则呼叫无效的visual可能需要重新安排后代控件,甚至需要重新测量。但是我相信,如果WPF的可用空间不变,则可以防止后代控制对后代进行重新排列。

您可以通过将渲染逻辑转移到单独的控件(例如NestedControl)来解决这个问题,这将是MainControl的视觉孩子。主控制器可以自动将其添加为视觉儿童,也可以作为其ControlTemplate的一部分,但是它需要是Z阶中最低的孩子。然后您可以暴露 InvalidateNestedControl 在MainControl上的键入方法,该方法将在NestedControl上调用InvalidateVisual。

你不应该打电话 InvalidateVisual() 除非您的控制大小改变,即使这样,还有其他方法可以引起重新延期。

为了有效地更新控件的视觉视觉,而无需更改其大小。用一个 DrawingGroup. 。您可以创建绘图组并将其放入 DrawingContext 期间 OnRender() 然后任何时间都可以 Open()DrawingGroup 要更改其视觉绘图命令,WPF将自动 并有效 重新渲染UI的那部分。 (您也可以使用此技术 RenderTargetBitmap 如果您希望拥有可以进行增量更改的位图,而不是每次重新绘制)

这就是它的样子:

DrawingGroup backingStore = new DrawingGroup();

protected override void OnRender(DrawingContext drawingContext) {      
    base.OnRender(drawingContext);            

    Render(); // put content into our backingStore
    drawingContext.DrawDrawing(backingStore);
}

// I can call this anytime, and it'll update my visual drawing
// without ever triggering layout or OnRender()
private void Render() {            
    var drawingContext = backingStore.Open();
    Render(drawingContext);
    drawingContext.Close();            
}

private void Render(DrawingContext drawingContext) {
    // put your render code here
}

这是另一个黑客:http://geekswithblogs.net/newthingsilearned/archive/2008/08/25/refresh--update-wpf-controls.aspx

简而言之,您可以在优先dispatcherPriority.render中调用一些虚拟代表,这将导致优先级或以上的任何内容。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top