наблюдаемая коллекция не обновляется при изменении пользовательского интерфейса - PullRequest
2 голосов
/ 19 августа 2010

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

Пожалуйста, смотрите мой вопрос в конце поста.

- Customer.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace TestMVVM
{
    class Customer : INotifyPropertyChanged
    {
        private string firstName;
        private string lastName;

        public string FirstName
        {
            get { return firstName; }
            set
            {
                if (firstName != value)
                {
                    firstName = value;
                    RaisePropertyChanged("FirstName");

                }
            }
        }

        public string LastName
        {
            get { return lastName; }
            set
            {
                if (lastName != value)
                {
                    lastName = value;
                    RaisePropertyChanged("LastName");
                }
            }
        }

        #region PropertChanged Block
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, 
new PropertyChangedEventArgs(property));
            }
        }
        #endregion
    }
}

- UCTextBox.xaml

<UserControl x:Class="TestMVVM.UCTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="40" Width="200">
<Grid>
    <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl" 
             VerticalAlignment="Top" Width="120" />
</Grid>

- UCTextBox.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace TestMVVM
{
    /// 
    /// Interaction logic for UCTextBox.xaml
    /// 
    public partial class UCTextBox : UserControl, INotifyPropertyChanged
    {
        public UCTextBox()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(UCTextBox),
        new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(textChangedCallBack)));

        static void textChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
        {
            UCTextBox pasTextBox = (UCTextBox)property;
            pasTextBox.txtTextControl.Text = (string)args.NewValue;
        }

        public string Text
        {
            get
            {
                return (string)GetValue(TextProperty);
            }
            set
            {
                SetValue(TextProperty, value);
                NotifyPropertyChanged("Text");
            }
        }

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

- Window1.xaml

<Window x:Class="TestMVVM.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestMVVM"
Title="Window1" Height="300" Width="300">
<Grid>
    <local:UCTextBox x:Name="txtUC" />
    <Button Height="23" HorizontalAlignment="Left" Margin="39,0,0,82" 
            Name="btnUpdate" VerticalAlignment="Bottom" Width="75" Click="btnUpdate_Click">Update</Button>
    <Button Height="23" Margin="120,0,83,82" Name="btnChange" VerticalAlignment="Bottom" Click="btnChange_Click">Change</Button>
</Grid>

- Window1.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace TestMVVM
{
    /// 
    /// Interaction logic for Window1.xaml
    /// 
    public partial class Window1 : Window
    {
        CustomerHeaderViewModel customerHeaderViewModel = null;
        public Window1()
        {
            InitializeComponent();

            customerHeaderViewModel = new CustomerHeaderViewModel();
            customerHeaderViewModel.LoadCustomers();

            txtUC.DataContext = customerHeaderViewModel.Customers[0];

            Binding binding = new Binding();
            binding.Source = customerHeaderViewModel.Customers[0];
            binding.Path = new System.Windows.PropertyPath("FirstName");
            binding.Mode = BindingMode.TwoWay;

            binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

            txtUC.SetBinding(UCTextBox.TextProperty, binding);
        }

        private void btnUpdate_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(customerHeaderViewModel.Customers[0].FirstName);
        }

        private void btnChange_Click(object sender, RoutedEventArgs e)
        {
            txtUC.Text = "Tom";
        }
    }

    class CustomerHeaderViewModel
    {
        public ObservableCollection Customers { get; set; }

        public void LoadCustomers()
        {
            ObservableCollection customers = new ObservableCollection();

            customers.Add(new Customer { FirstName = "Jim", LastName = "Smith", NumberOfContracts = 23 });

            Customers = customers;
        }
    }
}

Когда я запускаю Window1.xaml, мой пользовательский элемент управления отображает данные как «Джим».Теперь, когда я изменяю текст на «Джон» и нажимаю «Обновить», в окне сообщения по-прежнему отображается «Джим», что означает, что наблюдаемая коллекция не обновляется.Когда я нажимаю кнопку «Изменить», пользовательский элемент управления изменяет данные на «Том».Теперь, когда я нажимаю кнопку «Обновить», в окне сообщений отображается «Том».Может кто-нибудь сказать мне, как добиться обновления наблюдаемой коллекции, изменяя данные в пользовательском контроле, а не через код?

Ответы [ 2 ]

2 голосов
/ 19 августа 2010

Это потому, что вы не обрабатываете событие txtTextControl.TextChanged, поэтому ваше свойство зависимости Text никогда не обновляется.

В любом случае вам не нужно обрабатывать это вручную с помощью DependencyPropertyChangedCallback и обработчика событий, вы можете просто связать txtTextControl.Text со свойством зависимости Text:

<TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl" 
         VerticalAlignment="Top" Width="120"
         Text="{Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:UCTextBox}}}"/>
0 голосов
/ 19 августа 2010

Наблюдаемая коллекция, только наблюдатели коллекции.Вы будете получать уведомления, когда элементы добавляются или удаляются, а не когда поля отдельных элементов изменились.Это нечто совершенно другое.Как сказал Томас Левеск, вам просто нужно связать правильную собственность.

...