OxyPlot — эта PlotModel уже используется каким-либо другим элементом управления PlotView

Я использую WPF и .NET 6.0. Мое приложение по сути представляет собой демонстрацию MVVM Джоша Смита с замененной бизнес-логикой. Код графика находится в проекте .NET 6.0, отдельном от приложения. Приложение имеет независимые рабочие области на отдельных вкладках. Я могу открыть несколько вкладок, некоторые с графиками, некоторые без, но если я попытаюсь вернуться на вкладку с графиками, я увижу сообщение об ошибке выше. Когда я пытаюсь вернуться на вкладку с графиками, я вижу, что представления создаются снова, как раз перед тем, как выдается исключение. Я без проблем использую этот же код в приложении .NET Framework 4.7.2.

Мой XAML:

<UserControl x:Class = "DataPlot.Views.BasicTrackView"
             xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local = "clr-namespace:DataPlot.Views"
             xmlns:oxy = "http://oxyplot.org/wpf"
             mc:Ignorable = "d" 
             d:DesignHeight = "450" d:DesignWidth = "800">
    <Grid>
        <oxy:PlotView x:Name = "Plot" Model = "{Binding PlotModel}" Grid.Column = "1" MinHeight = "{Binding MinimumPlotHeight}">
            <oxy:PlotView.DefaultTrackerTemplate>
                <ControlTemplate>
                    <oxy:TrackerControl Position = "{Binding Position}" LineExtents = "{Binding PlotModel.PlotArea}">
                        <oxy:TrackerControl.Background>
                            <LinearGradientBrush EndPoint = "0,1">
                                <GradientStop Color = "#f0e0e0ff" />
                                <GradientStop Offset = "1" Color = "#f0ffffff" />
                            </LinearGradientBrush>
                        </oxy:TrackerControl.Background>
                        <oxy:TrackerControl.Content>
                            <TextBlock Text = "{Binding}" Margin = "7" />
                        </oxy:TrackerControl.Content>
                    </oxy:TrackerControl>
                </ControlTemplate>
            </oxy:PlotView.DefaultTrackerTemplate>
        </oxy:PlotView>

    </Grid>
</UserControl>

Код позади:

public partial class BasicTrackView : UserControl
{
    public BasicTrackView()
    {
        InitializeComponent();
    }
}

У меня есть несколько подобных графиков в ItemsControl:

<UserControl x:Class = "DataPlot.Views.TrackContainerView"
             xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local = "clr-namespace:DataPlot.Views"
             xmlns:vm = "clr-namespace:DataPlot.ViewModels"
             xmlns:helpers = "clr-namespace:DataPlot.Helpers"
             mc:Ignorable = "d" 
             d:DesignHeight = "450" d:DesignWidth = "800">
    <UserControl.Resources>
        <DataTemplate DataType = "{x:Type vm:BasicTrackViewModel}">
            <local:BasicTrackView/>
        </DataTemplate>
        <DataTemplate DataType = "{x:Type vm:GenericTrackViewModel}">
            <local:GenericTrackView IsActive = "{Binding IsActive}"/>
        </DataTemplate>
        <DataTemplate DataType = "{x:Type vm:CollapsableTrackViewModel}">
            <local:CollapsableTrackView IsActive = "{Binding IsActive}"/>
        </DataTemplate>
    </UserControl.Resources>
    <Grid HorizontalAlignment = "Stretch" VerticalAlignment = "Stretch">
        <Grid.RowDefinitions>
            <RowDefinition Height = "30"/>
            <RowDefinition Height = "*"/>
        </Grid.RowDefinitions>
        <Label Grid.Row = "0" Content = "Controls?" Width = "60" Height = "25" HorizontalAlignment = "Right" Margin = "0,2,20,2" Grid.Column = "4"
               HorizontalContentAlignment = "Center" VerticalContentAlignment = "Center" Background = "LightGray">
            <Label.ToolTip>
                <ToolTip>
                    <DockPanel Width = "200" Height = "75">
                        <TextBox Text = "Zoom: Ctrl + Right Mouse, or&#x0a;Zoom with mouse wheel&#x0a;Pan: Right Mouse" AcceptsReturn = "True"/>
                    </DockPanel>
                </ToolTip>
            </Label.ToolTip>
        </Label>

        <ScrollViewer Grid.Row = "1" VerticalScrollBarVisibility = "Auto" HorizontalScrollBarVisibility = "Auto">
            <ItemsControl Grid.Row = "1" ItemsSource = "{Binding TrackViewModels}" HorizontalAlignment = "Stretch" VerticalAlignment = "Stretch">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Grid helpers:GridHelpers.RowCount = "{Binding TrackViewModels.Count}" helpers:GridHelpers.StarRows = "All"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemContainerStyle>
                    <Style>
                        <Setter Property = "Grid.Row" Value = "{Binding RowIndex}" />
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>
        </ScrollViewer>

    </Grid>
</UserControl>

Могу ли я что-то сделать, чтобы приложение не пыталось воссоздать уже существующие представления?

Я видел то же самое, и этот пост на их github очень помог. Я реализовал ViewResolvingPlotModel и использовал его вместо PlotModel в своей модели представления, и проблема исчезла. Я не уверен, что это будет работать непосредственно в xaml, но это подчеркивает проблему. github.com/oxyplot/oxyplot/issues/497#issuecomment-322268584

bigcrazyal 27.02.2024 15:23

Спасибо. Я опубликовал ваше решение в качестве ответа.

spainchaud 27.02.2024 21:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
90
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я хотел бы выразить благодарность bigcrazal (в его комментарии) за предоставление простого решения с помощью ссылки на код, предоставленный Эдвинашем. Поскольку ссылки могут испортиться, я приведу код ниже. В своем вопросе я упомянул, что у меня не было проблем с этим кодом в старых проектах .NET Framework 4.7.2. Теперь я считаю, что это потому, что я использовал статические вкладки в своих прошлых приложениях.

using System;
using System.Linq;
using System.Reflection;
using OxyPlot;

/// <summary>
/// Use this sub implementation of the <see cref = "PlotModel"/> if the view will be declared using data template.
/// Because views will be automatically generated, and new view will be different this causes current version to throw an error.
/// </summary>
public class ViewResolvingPlotModel : PlotModel, IPlotModel
{
    private static readonly Type BaseType = typeof(ViewResolvingPlotModel).BaseType;
    private static readonly MethodInfo BaseAttachMethod = BaseType
        .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)
        .Where(methodInfo => methodInfo.IsFinal && methodInfo.IsPrivate)
        .FirstOrDefault(methodInfo => methodInfo.Name.EndsWith(nameof(IPlotModel.AttachPlotView)));

    void IPlotModel.AttachPlotView(IPlotView plotView)
    {
        //because of issue https://github.com/oxyplot/oxyplot/issues/497 
        //only one view can ever be attached to one plotmodel
        //we have to force detach previous view and then attach new one
        if (plotView != null && PlotView != null && !Equals(plotView, PlotView))
        {
            BaseAttachMethod.Invoke(this, new object[] { null });
            BaseAttachMethod.Invoke(this, new object[] { plotView });
        }
        else
        {
            BaseAttachMethod.Invoke(this, new object[] { plotView });
        }
    }
}

Другие вопросы по теме