(WPF / C#)使用DispatcherTimer进行UI更新循环

时间:2017-08-07 07:43:10

标签: c# wpf

我有一个应用程序,我有一个带有多个交互式UI元素的View。另外,我有一个DispatcherTimer每10秒运行一次UI更新。我创建了一个自定义动态网格,根据动态网格有多少个孩子来排列子元素。

但是,我有一个问题。当计时器触发时,动态网格在更新元素时​​陷入循环,我不知道为什么。这是代码的简化版本,请务必告诉我它是否不足:

MainWindow.xaml.cs

    public MainWindow()
    {
        InitializeComponent();

        main = new MainView(pollCollectionMain);


        RefreshTimer = new DispatcherTimer();
        RefreshTimer.Tick += new EventHandler(OnTimedEvent);
        RefreshTimer.Interval = new TimeSpan(0, 0, 10);
        RefreshTimer.Start();

    }

    private void OnTimedEvent(object sender, EventArgs e)
    {   
        //The Polling class has a variable output
        pollObj = new Polling();
        pollCollectionMain = pollObj.PollingCollection;
        main = new MainView(pollCollectionMain);
    }

main.cs

    public MainView(ObservableCollection<PollingData> pollLocal)
    {
        dynGrid = new DynamicGrid();
        p = pollLocal;

        for (int i = 0; i < p.Count; i++)
        {
            //Making some new controls
            //ControlGrid is just a Grid with mouse functionality
            mainControlGrid = new ControlGrid();
            mainControlGrid.Children.Add(someControl);
            dynGrid.Children.Add(mainControlGrid);
        }

    }

DynamicGrid(),发生无限循环

    public DynamicGrid()
    {

        _currentChildrenCount = 0;

        //The following is the infinite loop
        LayoutUpdated += (s, e) =>
        {
            if (Children?.Count != _currentChildrenCount)
            {
                _currentChildrenCount = (Children != null) ? Children.Count : 0;
                OnNumberOfItemsChangedImpl();
            }
        };
    }

1 个答案:

答案 0 :(得分:0)

您不应该在WPF中管理这样的布局。 WPF有一种内置的管理方式:使用Panel。

public class YourPanel : Panel {

    protected override Size MeasureOverride(Size availableSize) {
        if (InternalChildren.Count == 0) return new Size(0, 0);
        //Measure each children's size and then compute and return the size the panel needs to display correctly

        foreach(UIElement children in InternalChildren) {
            children.Measure(sizeYouWantToGiveToTheElement);
        }

        return totalSizeYourPanelNeeds;
    }

    protected override Size ArrangeOverride(Size finalSize) {
        if (InternalChildren.Count == 0) return new Size(0, 0);

        //Arrange each element in the panel according to your own rules
        for (int i = 0; i < InternalChildren.Count; i++) {
            UIElement children = InternalChildren[i];

            //Arrange the panel's children at the position you want and with the size you want
            children.Arrange(new Rect(childrenPosition, childrenSize));
        }

        return finalSize;
    }
}

除非您这样做,否则您将进行不必要的更新并打扰调度员。

您可以在ItemsControl中使用您的面板:

<ItemsControl ItemsSource="{Binding Path=YourItems, Mode=OneWay}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <YourPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

您可以在自定义面板herehere中找到更多相关信息。