【问题标题】:Silverlight MVVM - Twoway binding not fired on Listbox clickSilverlight MVVM - 列表框单击时未触发双向绑定
【发布时间】:2010-08-30 16:26:30
【问题描述】:

在 Silverlight MVVMLight 4.0 应用程序中,我有一个列表框、一个文本框和一个复选框。 列表框的 ItemsSource 绑定到视图模型中的对象列表。 列表框的 SelectedItem 双向绑定到 viewmodel 中的对象 (SelectedActivity)。

文本框的 Text 和复选框的 IsSelected 属性都是双向绑定到视图模型中的 SelectedActivity 对象(Name 和 Selected 属性)的。 没有代码隐藏。

这很好用:更改文本框中的名称或选中/取消选中复选框,然后按 Tab 键将更改对象的基础属性。

但是当我更改名称(或选中状态)然后立即单击列表中的另一个项目时,更改未注册。

有人有解决办法吗?

亲切的问候,

卡雷尔

这是 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}">

这是包含绑定到列表的项目的活动类:

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();
    }
}        

【问题讨论】:

  • 如果您至少发布了您的视图模型/视图代码的相关部分,这将有所帮助。您的列表是 ObservableCollection 并且您的视图模型实现了 INotifyPropertyChanged?
  • 是的,列表绑定到 ObservableCollection 并且视图模型正在实现 INotifyPropertyChanged。我使用了 MVVMLight 模板。我将使用相关代码更新问题。

标签: silverlight binding mvvm-light


【解决方案1】:

我遇到了同样的问题。我必须在用户输入文本时触发更新,以便进行一些验证。

实现此目的的一种简单方法是创建自定义行为,然后您可以将其添加到任何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();
        }
    }
}

然后你像这样将它设置为TextBoxBehaviors 是我将类放在上面的命名空间):

 <TextBox Behaviors:TextChangedBindingBehavior.Instance="" Text="{Binding Name, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" />

【讨论】:

    【解决方案2】:

    我在使用 TextBox 时遇到过类似的问题,但没有看到它影响复选框。 TextBox 问题正在发生,因为绑定文本得到更新然后焦点丢失。这就是为什么如果您先按标签然后更改您的选择,它会按预期工作。如果您更改选择直接绑定文本不会得到更新,因为焦点丢失消息到达太晚。

    处理此问题的一种方法是在每次用户在文本框中键入文本时强制更新绑定。您可以进行自定义行为以保留它 mvvm。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 2011-05-27
      • 1970-01-01
      • 2011-08-16
      • 1970-01-01
      • 2014-05-24
      • 1970-01-01
      相关资源
      最近更新 更多