Silverlight UserControl и MVVM - PullRequest
       12

Silverlight UserControl и MVVM

1 голос
/ 06 июня 2009

У меня очень похожая проблема, как описано в этом посте .

У меня есть UserControl для инкапсуляции адреса. Он содержит ряд основных элементов управления, в основном текстовые поля. Затем у меня есть вспомогательные свойства зависимостей в коде для каждого свойства ...

#region Line1

    /// <summary> 
    /// Gets or sets the Line1.
    /// </summary> 
    public string Line1
    {
        get
        {
            return (string)GetValue(Line1Property);
        }

        set
        {
            SetValue(Line1Property, value);
        }
    }

    /// <summary> 
    /// The Line1 dependency property.
    /// </summary> 
    public static readonly DependencyProperty Line1Property =
                DependencyProperty.Register(
                      "Line1",
                      typeof(string),
                      typeof(AddressControl),
                      new PropertyMetadata(OnLine1PropertyChanged));

    /// <summary>
    /// Line1Property property changed handler. 
    /// </summary>
    /// <param name="d">AddressControl that changed its Line1.</param>
    /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
    private static void OnLine1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as AddressControl;
        if (control != null)
        {
            control.OnLine1Changed((string)e.OldValue, (string)e.NewValue);
        }
    }

    /// <summary>
    /// Called when the Line1 changes.
    /// </summary>
    /// <param name="oldValue">The old value.</param>
    /// <param name="newValue">The new value.</param>
    private void OnLine1Changed(string oldValue, string newValue)
    {
        Line1TextBox.Text = newValue;
    }

    #endregion Line1

Затем я использую этот элемент управления в представлении ...

<myControls:AddressControl Grid.Row="0" Grid.Column="3" 
                           Line1="{Binding Path=Line1, Mode=TwoWay}"/>

Похоже, это устанавливает значение текстового поля при обновлении свойства модели представления, как и следовало ожидать, однако моя проблема заключается в получении обновления от usercontrol обратно к модели представления?

По ссылке выше я должен проверить мой DataContext на элементе управления. Surley DataContext будет таким же, как родительский?

Я надеюсь, что ответ на этот вопрос будет применяться к нескольким уровням вложенности элементов управления, т.е. Control1 используется в Control2, который используется в Control3, весь смысл повторного использования!

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

Ответы [ 3 ]

3 голосов
/ 06 июня 2009

В MVVM вы должны связываться со свойствами ViewModel, а не со свойствами, определенными в коде вашего элемента управления

0 голосов
/ 08 июня 2009

Похоже, что код для UserControl используется для предоставления свойств, с которыми связан сам элемент управления. В этом случае у вас, вероятно, есть некоторый код, такой как «this.DataContext = this» или «this.AddressLine1Control.DataContext = this», который может быть проблематичным (он даже вызывает сбой SL2) Создайте отдельный класс для хранения ваших свойств данных, затем сделайте что-то вроде «this.DataContext = new MyAddressClass ().» Вы заметите, что DataContext распространяется по всему дереву элементов управления так, что вложенные элементы управления наследуют DataContext своего родителя, как и следовало ожидать.

Кроме того, здесь не похоже, что вам нужны DependencyProperties. Вместо этого было бы проще создать традиционные свойства CLR и реализовать интерфейс INotifyPropertyChanged в вашем классе данных (при условии, что вы отделяете данные от класса UserControl). Это стандартный и рекомендуемый способ связывания данных в SL2.

0 голосов
/ 07 июня 2009

Не думаю, что сначала я достаточно хорошо объяснил себя, а также думаю, что нашел решение.

для других; Моя цель состояла в том, чтобы создать простой пользовательский элемент управления для инкапсуляции адреса (строки 1–4 и почтовый индекс, который говорил вам, что это просто), состоящий из текстовых ящиков для использования на многих страницах (иногда они использовались более одного раза на одной странице). Каждая из этих страниц (просмотров) поддерживается ViewModel из шаблона MVVM. Пока это все стандартно. То, что я не мог понять, было то, как получить изменение в любом из этих текстовых полей, чтобы вернуться обратно к ViewModel страницы, содержащей AddressControl. Со мной?

Поскольку оказывается, что решение (и теперь это кажется очевидным) заключалось в обработке потерянного фокуса каждого текстового поля и обновлении свойства зависимости, это приводит к тому, что привязка запускается до модели представления.

private void AddressTextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        switch (((TextBox)sender).Name)
        {
            case "Line1TextBox":
                Line1 = Line1TextBox.Text;
                break;

            case "Line2TextBox":
                Line2 = Line2TextBox.Text;
                break;

            case "Line3TextBox":
                Line3 = Line3TextBox.Text;
                break;

            case "Line4TextBox":
                Line4 = Line4TextBox.Text;
                break;

            case "LinePostcodeTextBox":
                Postcode = PostcodeTextBox.Text;
                break;
        }
    }

Другим вариантом было привязать текстовые поля к вспомогательной ViewModel в коде позади элемента управления и внести изменения в это обновление элементов управления. Тот же эффект с использованием локальной привязки, а не обработки событий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...