【问题标题】:WPF using Helix Tool, PropertyChangedEventHandler is always null while trying to update ModelVisual3D viewWPF 使用 Helix 工具,PropertyChangedEventHandler 在尝试更新 ModelVisual3D 视图时始终为空
【发布时间】:2021-10-11 21:03:03
【问题描述】:

我是 WPF 新手,在更改后尝试更新主窗口 UI 时遇到问题。

我有以下 MainWindow.xaml(我会展示其中的一部分,因为它很大)

<Window
    x:Class="SimpleDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:HelixToolkit="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
    xmlns:local="clr-namespace:SimpleDemo"
    Title="Plot 3D data"
    Width="680"
    Height="680" WindowStartupLocation="CenterScreen">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

下一个重要部分是主窗口的 3D 绘图部分,我将绘图的内容与名为 Model 的 Model3D 对象绑定。

            <!--  Remember to add light to the scene  -->
            <HelixToolkit:SunLight />

            <!--  The content of this visual is defined in MainViewModel.cs  -->
            <ModelVisual3D Content="{Binding Path = Model, Mode=OneWayToSource,NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" />

            <!--  You can also add elements here in the xaml  -->
            <HelixToolkit:GridLinesVisual3D
                Width="800"
                Length="800"
                MajorDistance="15"
                MinorDistance="15"
                Thickness="0.05" />

        </HelixToolkit:HelixViewport3D>
        <StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
            <Button Margin="5" Click="Backward_Click">Backward</Button>
            <Button Margin="5" Click="Forward_Click">Forward</Button>
        </StackPanel>

该程序的想法是从一个 txt 文件中读取前 500 个数据点 (x,y,z),然后使用 Helix Toolkit 从那些数据点创建一个 AddRectangularMesh()。我对多组点执行此操作,最后我得到了一个包含多个 AddRectangularMesh() 对象的网格。之后,我将最终结果显示到 HelixViewport3D。 在 UI 中,我有两个按钮前进和后退。前进按钮正在尝试从 txt 文件中绘制接下来的 500 个点。

在我的 MainWindow.xaml.cs 文件中,我调用按钮的事件处理程序,该处理程序调用 MainViewModel.cs 文件中的函数,在该文件中计算该数据点的所有函数,最终结果将保存在 Model3D 模型对象上,然后必须在 UI 上绘制。

按钮调用 Forward_click 事件并增加计数器以读取下一个数据点

&lt;Button Margin="5" Click="Forward_Click"&gt;Forward&lt;/Button&gt;

按下按钮后,事件处理程序被调用,但它为空,因此 UI 永远不会更新,我无法显示下一个数据点。 在我的代码中,我已经实现了事件处理程序,以监听模型的变化,因此在函数执行后模型对象将被更新,然后调用处理程序来更新 UI。

MainViewModel 类定义为:

    public class MainViewModel : Window, INotifyPropertyChanged

和事件处理程序如下:

        private Model3D model;
        public Model3D Model 
        { 
            get { return model; }
            set 
            {
                model = value;
                OnPropertyChanged(nameof(Model));
            } 
        }

        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, e);
        }

        protected void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

我在代码上放置了断点,当我按下按钮时,处理程序被调用但为空,然后没有更新或完成,该函数使用新点计算新的 Model3D 对象,但不绘制新结果.

如果我在 public MainViewModel() 部分运行相同的函数,则会显示前 500 个点,但这是由于第一次运行窗口所致。

这是每次按下按钮后模型对象的更新方式。

public void CoreCalculations()
        {
            for (int i = 0 ; i < 500; i++)
            {
                //read File Line
                // --- Do something with the points ---
                // create a mesh using the points and AddRectangularMesh
            }
            MeshGeometry3D mesh = meshBuilder.ToMesh(true);
            Material blueMaterial = MaterialHelper.CreateMaterial(Colors.Blue);
            modelGroup.Children.Add(new GeometryModel3D { Geometry = mesh, Transform = new TranslateTransform3D(2, 0, 0), Material = blueMaterial, BackMaterial = blueMaterial });
            Model = modelGroup;
        }

【问题讨论】:

    标签: c# wpf helix-3d-toolkit


    【解决方案1】:

    尝试将OneWayToSource 更改为OneWay。来自documentation

    当目标属性改变时更新源属性。

    你可能想反过来做。每当模型更改时更新目标。

    MainViewModel 继承自 Window 有点奇怪。我建议看一下 helix3D“SimpleDemo”。只是为了确认更改模型有效,使 mainViewModel 继承 INotifyPropertyChanged,并添加以下代码:

            private async Task RemoveModel()
            {
                await Task.Delay(5000);
                Model = null;
                OnPropertyChanged(nameof(Model));
            }
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    
    

    并在构造函数中调用RemoveModel。那应该使模型在 5 秒后被删除。请注意,示例代码适合调试,仅此而已。

    您还应该能够使用live visual tree explorer 来帮助调试 UI。

    【讨论】:

    • 我确实将模式更改为 OneWay,但调试仍然显示处理程序为空,并且 UI 上没有任何更新。我有想法在 Core 函数执行后执行 MainWindow.Refresh 之类的操作,但我没有找到任何用于此目的的方法。
    • @FosDrogg Gmr 添加了一些关于其他可能不正确的内容的注释。
    • 是的,我对 MainViewModel : Window 也有同样的想法,但示例项目取自原始 Helix Toolkit github 示例程序。我试图在其中添加我的功能。也许 DataContext 的某些东西无法正常工作,我无法将数据显示到主窗口?
    • 您的最终回答对我重新考虑我的代码有很大帮助。我将您的想法与我的想法结合起来,并设法创建了在 3D 视图中添加更多点所需的功能。非常感谢!
    • 我尝试了其他方法,如果我在 MainViewModel 构造函数中调用 RemoveModel 任务,程序会按预期清除 3D 图,但是如果我在构造函数完成执行后调用 RemoveModel 任务,则没有任何变化并且事件处理程序为空。
    猜你喜欢
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    相关资源
    最近更新 更多