【问题标题】:How to wait for WPF UI?如何等待 WPF UI?
【发布时间】:2021-09-15 20:47:03
【问题描述】:

我最近在尝试更新 ObservableCollection 绑定到堆栈面板时遇到 WPF UI 问题。

我在 WPF 中有一个 StackPanel,其中包含自定义 UserControl。所有这些 UIElement 都在名为“参数”的 ObservableCollection 中。我有他们这样的:

        Parametres.Clear();
        foreach(UIElement uie in SReference.UIEList)
        {
            Parametres.Add(uie);
        }

方法调用时,我清除旧参数ObservableCollection,直接设置新的。

该方法没有任何问题,只是当我快速更改新参数列表时,UI 会错过其中的一些。 UI 没有跳过它们,似乎跳过了渲染
但是当我更改UI大小或刷新某些东西时,突然出现参数

是否有刷新 UI 或等待列表中每个 UIElement 的 UIElement 渲染的方法?

更多详情:

此应用程序是插件,允许用户在 3D 设计软件中创建自定义 3D 模型。目标是跨越不同的模型参考并向用户显示可以在插件内编辑的参数。

我有一个包含功能区和主要内容部分的窗口。必要时更改此主要内容部分。

这是我遇到问题的主要内容部分。

1- 用户选择模型类别

2- 用户选择产品

3- 用户选择标准参考或自定义参考

4- 用户编辑参数

这个模型有很多属性和一些方法,比如上面的那个。 3D 模型类别是 ObservableCollection ComboBox 内容绑定到两个 ObservableCollection 并且包含参数的堆栈面板绑定到 ObservableCollection

每次您在第 1 步、第 2 步或第 3 步更改某些内容时,ObservableCollection 都会清楚并获取(或不获取)一些新元素。 有元素是由主模型类生成的。

stackpanel 中的每个 UIElement 都是自定义用户控件。我有两种:

  • 长度参数
  • 是 否 参数

这是“SReference.UIEList”背后的代码

    private List<UIElement> uieList;
    public List<UIElement> UIEList 
    {
        get
        {
            uieList.Clear();
            // On ajoute tous les éléments d'interface dans la liste.
            foreach(LengthParameterModelView parametre in parameters)
            {
                uieList.Add(parametre.lp);
            }

            string lastGroupeOption = "";

            foreach (OptionParameterModelView option in options)
            {
                if(lastGroupeOption == "" || option.NomGroupe != lastGroupeOption)
                {
                    lastGroupeOption = option.NomGroupe;

                    // Création du label du groupe d'options
                    Label l = new Label();
                    l.Margin = new Thickness(5, 0, 10, 0);
                    l.Style = ProduitAssocié.SousSectionUI.Resources["OptionLabel"] as Style;
                    l.Content = option.NomGroupe;

                    uieList.Add(l);
                }
                uieList.Add(option.ynp);
            }
            return uieList;
        }
    }

parametre.lp是长度参数的ViewModel生成的UIElement

option.ynp是yes no参数的ViewModel生成的UIElement

希望这会有所帮助。

【问题讨论】:

  • 您应该在 ItemTemplate 中将 ItemsControl 与 UserControl 一起使用。
  • 这不相关,是不是:stackoverflow.com/q/82847/982149?
  • @Clemens 你的意思是改变 UserControl 为 ItemControl ?
  • @Fildor 并不是因为我的方法不能异步工作。它位于我的模型部分。
  • Data Templating Overview。 UserControl 应在用作 ItemsControl 的 ItemTemplate 的 DataTemplate 中声明。因此,它将用于可视化 ItemsSource 集合中的单个数据项,这将是数据项的 ObservableCollection。

标签: c# wpf


【解决方案1】:

您很可能在渲染父级时调用了您显示的代码。
在这种情况下,可能会出现子元素已经被评估并且在下一次渲染之前不会重绘的情况。

将此代码移动到调度程序的单独异步任务中可能会对您有所帮助。

补充。 如果您在 UserControl 或 Window 的代码之外调用该方法,则您没有 Dispatcher 属性。
然后您可以从应用程序中获取它:

    Dispatcher.BeginInvoke((Action)(() =>
    {
        Parametres.Clear();
        foreach (UIElement uie in SReference.UIEList)
        {
            Parametres.Add(uie);
        }
    }));

我在这里遇到了类似的问题:How to defeat a bug with Grid.Row / Column in ItemsPanelTemplate?
一个类似的解决方案帮助了我。

    Application.Current.Dispatcher.InvokeAsync(() => 
    { 
        Parametres.Clear();
        foreach (UIElement uie in SReference.UIEList)
        {
            Parametres.Add(uie);
        }
    });

【讨论】:

  • 在 ViewModel 的集合中包含 UIElements 仍然感觉不对。我同意 Clemens 关于使用 DataTemplate 的建议。其他说明:最好使用InvokeAsync() 而不是BeginInvoke()(它允许删除Action 的演员表)。
  • @Arkane,我完全同意你的看法。但是从显示的代码和解释来看,我认为这是关于 View 内部的实现,这里不涉及 ViewModel。在这里使用 FreezableCollection 而不是 ObservableCollection 可能会更好。
  • 你能给我更多的信息来使用这个 sn-ps 吗?只需复制并粘贴它,但与智能感知相比,这会给我带来一些错误。谢谢。
  • 复制替换原代码就足够了。您可能在复制时删除了括号、逗号或犯了其他一些小错误。没有看到完整的代码,我无法判断错误是什么。并显示错误的全文(和屏幕截图)。
  • 您正在使用此代码而不是您的 UserControl 背后的代码(正如我所想的那样)。而 Dispatcher 是 DispacherObject 实例的一个属性(包括任何 UI 元素)。从Application.Current.Dispatcher.InvokeAsync (...) 获取。我补充了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多