Silverlight MVVM - Twoway привязка не срабатывает при нажатии Listbox - PullRequest
2 голосов
/ 30 августа 2010

В приложении Silverlight MVVMLight 4.0 у меня есть список, текстовое поле и флажок.ItemsSource этого списка привязан к списку объектов в модели представления.SelectedItem списка имеет двустороннюю привязку к объекту (SelectedActivity) в модели представления.

И свойства Text текстового поля, и флажок IsSelected имеют двустороннюю привязку к объекту SelectedActivity (свойства Name и Selected) вViewModel.Нет никакого кода позади.

Это прекрасно работает: изменение имени в текстовом поле или установка / снятие флажка и последующая вкладка изменят основное свойство объекта.

Но когда я изменяюимя (или проверенное состояние), а затем немедленно щелкните другой элемент в списке, изменение не зарегистрировано.

У кого-нибудь есть обходной путь для этого?

С уважением,

Karel

Это XAML:

<ListBox Height="251" HorizontalAlignment="Left" Margin="11,39,0,0" Name="activitiesListBox" ItemsSource="{Binding Activities.Items}" VerticalAlignment="Top" Width="139"
             SelectedItem="{Binding Activities.SelectedActivity, Mode=TwoWay}">

Это класс Activity, содержащий элементы, привязанные к списку:

public class CLJActivitiesViewModel : ViewModelBase
{
    /// <summary>
    /// Initializes a new instance of the ActivitiesViewModel class.
    /// </summary>
    public CLJActivitiesViewModel()
    {
        ////if (IsInDesignMode)
        ////{
        ////    // Code runs in Blend --> create design time data.
        ////}
        ////else
        ////{
        ////    // Code runs "for real": Connect to service, etc...
        ////}
    }


    #region items
    /// <summary>
    /// The <see cref="Items" /> property's name.
    /// </summary>
    public const string ItemsPropertyName = "Items";

    private ObservableCollection<CLJActivityViewModel> m_Items = null;

    /// <summary>
    /// Gets the Items property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public ObservableCollection<CLJActivityViewModel> Items
    {
        get
        {
            return m_Items;
        }

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

            var oldValue = m_Items;
            m_Items = value;

            RaisePropertyChanged(ItemsPropertyName, oldValue, value, true);
        }
    }
    #endregion

    #region SelectedActivity
    /// <summary>
    /// The <see cref="SelectedActivity" /> property's name.
    /// </summary>
    public const string SelectedActivityPropertyName = "SelectedActivity";

    private CLJActivityViewModel m_SelectedActivity = null;

    /// <summary>
    /// Gets the SelectedActivity property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public CLJActivityViewModel SelectedActivity
    {
        get
        {
            return m_SelectedActivity;
        }

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

            var oldValue = m_SelectedActivity;
            m_SelectedActivity = value;

            RaisePropertyChanged(SelectedActivityPropertyName, oldValue, value, true);
        }
    }
    #endregion



    public override void Cleanup()
    {
        // Clean own resources if needed

        base.Cleanup();
    }
}        

Ответы [ 2 ]

1 голос
/ 01 сентября 2010

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

Простой способ добиться этого - создать пользовательское поведение, которое затем можно добавить к любому TextBox.

Мой выглядит следующим образом:

public static class TextChangedBindingBehavior
{
    public static readonly DependencyProperty InstanceProperty =
        DependencyProperty.RegisterAttached("Instance", typeof(object), typeof(TextChangedBindingBehavior), new PropertyMetadata(OnSetInstanceCallback));


    public static object GetInstance(DependencyObject obj)
    {
        return (object)obj.GetValue(InstanceProperty);
    }

    public static void SetInstance(DependencyObject obj, object value)
    {
        obj.SetValue(InstanceProperty, value);
    }

    private static void OnSetInstanceCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBox = d as TextBox;
        if (textBox != null)
        {
            textBox.TextChanged -= OnTextChanged;
            textBox.TextChanged += OnTextChanged;
        }
    }

    private static void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var textBox = (TextBox)sender;

        if(!DesignerProperties.GetIsInDesignMode(textBox))
        {
            textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
        }
    }
}

, и вы устанавливаете его на TextBox вот так (Behaviors - это пространство имен, в котором я поместил класс выше):

 <TextBox Behaviors:TextChangedBindingBehavior.Instance="" Text="{Binding Name, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
1 голос
/ 30 августа 2010

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

Одним из способов решения этой проблемы является принудительное связывание обновлений каждый раз, когда пользователь вводит текст в текстовое поле. Вы можете сделать собственное поведение, чтобы сохранить его mvvm.

...