Привязка INotifyPropertyChanged обновляется не так, как ожидалось

#c# #silverlight #mvvm

#c# #silverlight #mvvm

Вопрос:

Итак, вот проблема, с которой я бьюсь головой: у меня есть пользовательский пользовательский элемент управления, который предоставляет два свойства зависимостей, которые привязаны к моей ViewModel. В моей ViewModel у меня есть экземпляр класса, который содержит несколько свойств, выражающих значения, относящиеся к пользовательскому элементу управления, а также к элементам, которыми управляет control. манипулирует. Вот немного примера кода, чтобы объяснить это визуально, так что вот простой пример моего элемента управления, это ползунок, который объединен с флажком, который позволяет пользователю блокировать ползунок.

     <custom:SliderControl IsLocked="{Binding Path=CustomClass.IsLocked, Mode=TwoWay}" SliderValue="{Binding Path=CustomClass.Value, Mode=TwoWay}" />
  

isLocked и sliderValue — это свойства зависимостей, которые эффективно управляют флажком и ползунком, содержащимися в пользовательском элементе управления. Все функции управления работают по назначению, за исключением привязок к определенному мной классу. Если я создаю отдельные свойства, как в одном свойстве int и одном свойстве bool, привязки работают так, как задумано. Однако у меня есть пять ползунков, и каждый ползунок в моем реальном коде имеет пять свойств, которые связаны с ними. Я пытаюсь устранить дублирование кода, создав класс для хранения этих свойств в повторно используемом объекте, сократив мои 25 свойств до 5 экземпляров класса.

Мой пользовательский класс наследует ObservableObject и имеет свойство bool и свойство int с именами isLocked и sliderValue соответственно. Для получения дополнительных наглядных пособий вот как это выглядит:

     public class CustomClass : ObservableObject
    {
        public const string SliderValuePropertyName = "SliderValue";
        private int _sliderValue= 0;
        public int SliderValue
        {
            get
            {
                return _sliderValue;
            }

            set
            {
                if (_sliderValue== value)
                {
                    return;
                }


                _sliderValue= value;
                RaisePropertyChanged(SliderValuePropertyName );
            }
        }

    public const string IsCheckedPropertyName = "IsChecked";
    private bool _isChecked = false;
    public bool IsChecked
    {
        get
        {
            return _isChecked;
        }

        set
        {
            if (_isChecked == value)
            {
                return;
            }
            _isChecked = value;
            RaisePropertyChanged(IsCheckedPropertyName);
        }
    }
  

Свойство ViewModel очень похоже и выглядит следующим образом: при загрузке ViewModel создается новый экземпляр класса:

     public const string SliderOnePropertyName = "SliderOne";
    private CustomClass _sliderOne;
    public CustomClass SliderOne
    {
        get
        {
            return _sliderOne;
        }

        set
        {
            if (_sliderOne== value)
            {
                return;
            }

            _sliderOne= value;
            RaisePropertyChanged(SliderOnePropertyName );
        }
    }
  

Почему обновление свойства зависимости, которое привязано к свойству в классе, не обновляется должным образом? Это потому, что вы не можете правильно обновить свойство экземпляра класса само по себе и вместо этого должны обновлять весь экземпляр класса всякий раз, когда происходят изменения? Или мне нужно дополнительно настроить установщик в этом свойстве ViewModel? Поскольку он находится сейчас, изменение значения ползунка или флажка вообще никогда не попадает в свойство bound, и при отладке ничего не выдает ошибок.

РЕДАКТИРОВАТЬ: я также окружил элемент управления границей и установил DataContext DataContext элемента управления Border для класса, а затем впоследствии применил более простую привязку пути к базовому пользовательскому элементу управления. Однако это никак не повлияло на мою проблему.

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

Буду признателен за любую помощь.

РЕДАКТИРОВАТЬ: итак, я поиграл с использованием пользовательского события, которое сообщит мне, когда изменится конкретное свойство пользовательского элемента управления, а затем подключил это событие в мою ViewModel для обновления существующего класса. Это работает, но все равно создает дублирование кода, так как теперь у меня должно быть 10 событий, по 2 события на элемент управления, одно для проверки при изменении значения ползунка, а другое для определения изменения значения флажка. Это дублирование кода существует, поскольку вы не можете маршрутизировать несколько параметров команды (например, простой строковый идентификатор, для которого выполняется управление ползунком, а также значение, которое вы хотите использовать в коде). Это ограничение означает, что я не могу просто использовать 2 события, которые различают, какой элемент управления претерпевает изменения в рамках определенного метода, поскольку предоставление физического элемента управления ViewModel нарушает шаблон MVVM. Использование класса в качестве datacontext для пользовательского элемента управления сделало так, что мне было все равно, каким элементом управления манипулируют, поскольку у каждого из них был свой собственный экземпляр класса. Используя события, это раскрывает шаблон MVVM, поскольку теперь мне нужно знать, каким из пяти элементов управления управляет пользователь.

Не может быть так сложно использовать класс в привязках свойств. Я должен упустить что-то исправительное.

Комментарии:

1. Вы проверили окно вывода на наличие ошибок привязки?

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

3. Какое DataContext значение для представления установлено?

4. DataContext представления устанавливается в ViewModel, присвоенный странице.

5. снова установите datacontext в пользовательском элементе управления SliderControl

Ответ №1:

вот полный пример:

 public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }
}


public class ViewModel
{
    public SliderValues slv { get; private set; }

    public ViewModel()
    {
        slv = new SliderValues();
    }
}

public class SliderValues : INotifyPropertyChanged
{
    bool _isLocked = false;

    public bool IsLocked
    {
        get { return _isLocked; }
        set
        {
            _isLocked = value;
            OnPropertyChanged("IsLocked");
        }

    }
    int _theValue = 5;

    public int TheValue
    {
        get { return _theValue; }
        set
        {
            _theValue = value;
            OnPropertyChanged("TheValue");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string prop)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(prop));

    }
}
  

Теперь xaml:

 <UserControl x:Class="TestBindings.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Slider Height="23" HorizontalAlignment="Left" Margin="114,138,0,0" Name="slider1" VerticalAlignment="Top" Width="100"
                DataContext="{Binding slv}" Value="{Binding TheValue, Mode=TwoWay}"/>
    </Grid>
</UserControl>
  

Комментарии:

1. Это именно то, где я сейчас нахожусь. Проблема, которую я создал для себя, заключалась в том, что я определил класс в отдельном файле и подумал, что мне нужно создать свойство для экземпляра класса, которое вызвало INotifyPropertyChanged в моей ViewModel, это скрывало, что все происходит в коде класса и игнорирует созданное мной свойство. Это затрудняет выполнение методов, которые полагаются на знание того, когда изменяются свойства класса. Я решаю эту проблему с помощью MVVM Light messaging. Спасибо за этот пример кода!

2. Причина, по которой у меня есть методы, которые выполняются при манипулировании любым отдельным элементом управления ползунком, заключается в том, что они взаимозависимы, и все они связаны с общим максимальным значением, которое, если оно будет достигнуто, начнет вымываться из элемента управления ползунком с наибольшим значением. Это создало ситуацию, когда мне понадобились все элементы управления при манипулировании, чтобы затем проверить все остальные элементы управления и создать четность, если был нарушен максимум.

Ответ №2:

Может быть, это просто синтаксическая ошибка. Попробуйте это

{Путь привязки=Пользовательский класс.Заблокирован, режим = TwoWay}

Комментарии:

1. Извините, в моем напечатанном примере действительно есть несколько опечаток, но в самом коде их нет. Теперь я их исправил.

Ответ №3:

Попробуйте это… <custom:SliderControl DataContext="{Binding CustomClass}" IsLocked="{Binding IsLocked, Mode=TwoWay}" SliderValue="{Binding Value, Mode=TwoWay}" />