Проблемы с привязкой пользовательского элемента управления WPF MVVM

Asked
Viewd3850

2

У меня есть приложение, использующее MVVM. У меня есть несколько элементов в главном окне, которые привязаны к ViewModel для этого окна. Когда запускаю все работает. Однако, когда я добавляю пользовательский элемент управления в главное окно и пытаюсь выполнить привязку к одному из его объектов зависимостей, он выдает исключение («Ссылка на объект не установлена ​​на экземпляр объекта»). Окно исключения просто появляется на экране и не ссылается на какое-либо конкретное место в коде. И любая другая информация в исключении бесполезна.

Я изо всех сил старался отследить это, но у меня ничего не вышло. В конструкторе окна я проверил и убедился, что элемент, к которому он пытается привязаться, существует и является объектом (int []). Я также вручную установил свойство в конструкторе с проблемами. Вот несколько фрагментов кода, если кто-то что-то заметит.

Здесь я использую пользовательский элемент управления и пытаюсь выполнить привязку к свойству 'view'

 <local:Histogram Grid.Row="2" Grid.ColumnSpan="2"
                                        View="{Binding Path=HistogramData}"             
                                        Foreground="{DynamicResource FontColor}"
                                        BucketStroke="{DynamicResource BucketStrokeBrush}"
                                        BucketFill="{DynamicResource BucketFillBrush}"
                                        SelectedBrush="{DynamicResource FamilyEditListViewSelectedBrush}"
                                        DisabledForegroundBrush="{DynamicResource DisabledForegroundBrush}"
                                        AxisBrush="{DynamicResource AxisBrush}" 
                                        MaxHeight="130" />
 

Вот поле в модели представления, к которому я пытаюсь привязать:

 public int[] HistogramData
    {
        get
        {
            return histogramData;
        }
        set
        {
            if (value != histogramData)
            {
                histogramData = value;
                RaisePropertyChanged("HistogramData");
            }
        }
    }
 

И в конструкторе модели представления я создаю экземпляр объекта

 histogramData = new int[256];
 

И, наконец, вот свойство представления в пользовательском элементе управления

 public static readonly DependencyProperty ViewProperty =
        DependencyProperty.Register("View", 
                                    typeof(int[]), 
                                    typeof(Histogram),
                                    new FrameworkPropertyMetadata(null,
                                                                  FrameworkPropertyMetadataOptions.AffectsRender,
                                                                  new PropertyChangedCallback(ViewProperty_Changed)));

    public int[] View
    {
        get { return (int[])GetValue(ViewProperty); }
        set { SetValue(ViewProperty, value); }
    }
 

Я не знаю, достаточно ли этой информации для решения чего-либо, поэтому, если требуется дополнительный код, сообщите мне. Я мог бы также заархивировать проект, если кто-то захочет на это взглянуть. Заранее спасибо.

2 ответов

2

Вы можете попробовать инициализировать массив при инициализации FrameworkPropertyMetaData в свойстве зависимости.

  new FrameworkPropertyMetadata(new int [256],
                              FrameworkPropertyMetadataOptions.AffectsRender,  
                              new PropertyChangedCallback(ViewProperty_Changed))
 

Я думаю, что программа могла бы вызвать исключение нулевой ссылки до того, как ей удастся привязать свойство зависимости к свойству viewmodel.


Хорошо, я просмотрел ваш пример проекта и думаю, что у меня есть решение.

измените int[] в модели просмотра на List<int>. Я не уверен, почему это работает.Надеюсь, нет технических причин, по которым list<int> вам не подходит.

Вот что я изменил в решении

в модели просмотра

 public List<int> CustomData
        {
            get
            {
                return new List<int>(){0,1,2,3};
            }
            set
            {
            }
        }
 

В коде управления массивом

 public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data",
                                        typeof(List<int>),
                                        typeof(ArrayControl),
                                        new FrameworkPropertyMetadata(new List<int>()));

        public List<int> Data
        {
            get { return (List<int>)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }
 

В arraycontrol.xaml.Просто добавлен список, чтобы показать работу привязки данных

 <UserControl x:Class="UserControlWithArray.Controls.ArrayControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid>
             <TextBlock x:Name="MessageTextBlock" Text="ArrayControl"/> 
        <ListBox ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=Data}"/>
    </Grid>
</UserControl>
 
  • Почему вы не используете методы ToList () и ToArray () для преобразования между ними по мере необходимости?

    Dave Turvey17 ноября 2009, 16:29
  • Если вы хотите отправить проект целиком, я посмотрю.Хотя я новичок в wpf, возможно, он тоже не работает.

    Dave Turvey17 ноября 2009, 14:04
  • Я пробовал это (см. мой последний комментарий выше), но это не сработало :(

    Dan dot net17 ноября 2009, 12:31
  • Я воссоздал проблему в очень маленьком проекте, который можно получить здесь: http://www.mediafire.com/?tjntymmi5dz.Он в формате rar, дайте мне знать, если это будет проблемой, и я могу его заархивировать.Спасибо

    Dan dot net17 ноября 2009, 14:55
  • Я знал, что использование списка работает (например, строка), но я действительно хочу использовать массив, чтобы я мог вставлять значения по индексу.Я предполагаю, что строка и список работают, потому что они могут быть нулевыми ??Спасибо, что нашли время взглянуть на него !!

    Dan dot net17 ноября 2009, 16:09
  • Извините, я не понимаю, какой комментарий вы имеете в виду.Вы пробовали заменить null в последнем фрагменте кода новым int [256]?

    Dave Turvey17 ноября 2009, 13:59
  • Я мог бы выполнить преобразование, но я подумал, что если мне нужен массив, я смогу делать то, что хочу, в массиве.Решение, которое я только что проверил и которое работает, - это поместить массив в класс и передать класс.Класс может иметь значение null, поэтому исключение не возникает.Я отмечу ваш ответ как принятый.Еще раз спасибо за вашу помощь

    Dan dot net17 ноября 2009, 16:55
1

Используйте отладчик, чтобы получить трассировку стека исключений.Это должно помочь вам сузить проблему.

Сделать это можно несколькими способами.Например, у вас должна быть возможность просто просмотреть детали исключения.Или вы можете открыть окно просмотра и ввести выражение $exception, а затем нажать кнопку «Оценить».

  • Обычно, если отладчик умирает, в InitializeComponent есть недопустимый xaml

    Nigel Sampson11 ноября 2009, 20:40
  • Ага, он должен быть в вашем xaml.InitializeComponent пытается создать экземпляры всех элементов управления, указанных в xaml.Это может быть средневековье, но попробуйте удалить элементы управления в своем .xaml, пока исключение не исчезнет.

    Jose12 ноября 2009, 04:41
  • Я создал новый пользовательский элемент управления только с одним объектом зависимости, который был строкой, и это сработало.Затем я изменил тип объекта зависимости на int [], и это не удалось так же, как и раньше.Я указываю в метаданных frameworkpropertymetadata, что значение по умолчанию - null, и я думаю, что это то, что меня облажает.Я попробовал «новый int [256]», но это тоже не удалось.Любые предложения по значению по умолчанию или если вы думаете, что я лаю не на то дерево.

    Dan dot net12 ноября 2009, 20:48
  • Когда я смотрю на детали (что я делал раньше), трассировка стека останавливается на «InitializeComponent ();» в коде главного окна позади.Если я войду в InitializeComponent, окно исключения появится в разных местах, и детали будут такими же, как и раньше.

    Dan dot net11 ноября 2009, 19:19