Элемент управления EmptyListBox не получает уведомления об изменении ItemsSouce (silverlight/wp7)

Пробовал, может подойти к отображению «нет данных», если в списке нет элементов. Поскольку я на wp7 и использую silverlight, я не могу использовать DataTriggers, поэтому я создал элемент управления, чтобы он вел себя последовательно во всем приложении. НО я, если вы установите точку останова для метода set - он вообще не вызывается!

Класс управления

public class EmptyListBox : ListBox
{
    public new IEnumerable ItemsSource
    {
        get 
        {
            return base.ItemsSource; 
        }

        set
        {    
            // never here
            base.ItemsSource = value;
            ItemsSourceChanged();
        }
    }

    protected virtual void ItemsSourceChanged()
    {
        bool noItems = Items.Count == 0;

        if (noItems)
        {
            if (Parent is System.Windows.Controls.Panel)
            {
                var p = Parent as Panel;

                TextBlock noData = new TextBlock();
                noData.Text = "No data";
                noData.HorizontalAlignment = HorizontalAlignment;
                noData.Width = Width;
                noData.Height = Height;
                noData.Margin = Margin;

                p.Children.Add(noData);
                Visibility = System.Windows.Visibility.Collapsed;
            }
        }
    }
}

это ксэмл

<my:EmptyListBox ItemsSource="{Binding Path=MyData}" Name="myListBox">
    <my:EmptyListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=name}" />
        </DataTemplate>
    </my:EmptyListBox.ItemTemplate>
</my:EmptyListBox>

Код программной части:

    ClientModel ClientInfo { get; set; }

    public ClientView()
    {
        ClientInfo = new ClientModel();
        ClientInfo.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(DataReady);

        DataContext = ClientInfo
    }

Класс ClientModel:

public class ClientModel : INotifyPropertyChanged
{
    MyData _myData;
    public MyData MyData 
    {
        get
        {
            return _myData;
        }

        set
        {
            _myData = value;
            NotifyPropertyChanged("MyData");
        }
    }

    public void GetClient(int id)
    {
        // fetch the network for data
    }
}   

ССЫЛКА НА РЕШЕНИЕ .ZIP, КОТОРОЕ ПОКАЗЫВАЕТ ПРОБЛЕМУ

http://rapidshare.com/files/455900509/WindowsPhoneDataBoundApplication1.zip

person argh    schedule 04.04.2011    source источник
comment
И где вы устанавливаете ItemsSource или DataContext страницы?   -  person Matt Lacey    schedule 04.04.2011
comment
В качестве рекомендации, если у вас возникли проблемы с кодом, опубликуйте все, что имеет отношение к делу, чтобы иметь возможность воссоздать проблему. Это включает в себя все пользовательские классы. - Что такое MyData?   -  person Matt Lacey    schedule 04.04.2011
comment
Серьезно, Мэтт, проблема НЕ в этом, поскольку выжидание работает. MyData — это POCO.   -  person argh    schedule 04.04.2011
comment
@argh Я пытался воссоздать то, что ты делаешь. Если я просто догадываюсь о коде, который у вас есть, то могу ли я заставить мой код работать, не имеет значения.   -  person Matt Lacey    schedule 04.04.2011
comment
хорошо, извините, но я просто ненавижу эти вопросы - я создал образец и отредактировал сообщение   -  person argh    schedule 05.04.2011


Ответы (5)


Ваш новый ItemSource должен быть DependencyProperty. Все, что работает с Bindings, должно быть DependencyProperty. Просто сделайте его DependencyProperty.

person Sonosar    schedule 06.04.2011
comment
Поправьте меня, если я ошибаюсь, но поскольку я наследую от ListBox, то это уже должно быть DependencyProperty? - person argh; 07.04.2011
comment
Когда вы объявляете dependencyProperty, вы также указываете ownerType. В вашем случае ownerType — EmptyListBox (по сравнению с ItemsControl исходного ItemsSource), вам нужно будет объявить свой собственный DependencyProperty, но, похоже, вы пытались, и это не помогает, что странно. В любом случае, возможно, у нас здесь есть и другая проблема, но тот факт, что ItemsSource должен быть DependencyProperty, это точно. - person Sonosar; 07.04.2011

Я думаю, что решение, которое я бы выбрал, выглядит примерно так:

  1. Define a new visual state group ItemsStates and two visual states: NoItems and HasItems.
    1. In the ControlTemplate for your custom listbox, add the visual tree for your "no data" state.
    2. В состоянии NoItems установите Visibility ваших элементов "без данных" на Visible и установите Visibility ItemsPresenter по умолчанию на Collapsed.
    3. В состоянии HasItems поменяйте местами Visibility этих элементов.
    4. В переопределении OnApplyTemplate переключитесь в состояние Empty по умолчанию: VisualStateManager.GoToState(this, "Empty", true);
    5. В переопределении OnItemsChanged проверьте, пуст ли источник элементов, и используйте VisualStateManager для переключения между этими состояниями соответственно.

Это должно сработать :)

person Derek Lakin    schedule 10.04.2011

Создайте ItemsSource как DependencyProperty.

Пример:

 public IEnumerable ItemsSource
 {
   get { return (IEnumerable)base.GetValue(ItemsSourceProperty); }
   set { base.SetValue(ItemsSourceProperty, value); }
 }

 public static DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register(
            "ItemsSource",
            typeof(IEnumerable),
            typeof(EmptyListBox),
            new PropertyMetadata(null));
person Gabe    schedule 04.04.2011
comment
это не работает... добавление "нового" к именам также не сработало... обратите внимание, что я наследую ListBox - person argh; 04.04.2011

попробуйте реализовать интерфейс INotifyPropertyChanged и используйте для ItemsSource наблюдаемаяколлекция. В Setter вашего свойства просто вызовите метод OnPropertyChanged.

Может быть, это поможет.

person cordellcp3    schedule 04.04.2011
comment
Модель клиента наследует INotifyPropertyChanged, и данные заполняются правильно. Проблема в том, что я не знаю, почему мои вещи не вызываются. - person argh; 04.04.2011

Попробуйте добавить Mode=TwoWay в привязку ItemsSource:

<my:EmptyListBox ItemsSource="{Binding Path=MyData, Mode=TwoWay}" Name="myListBox">
    <my:EmptyListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=name}" />
        </DataTemplate>
    </my:EmptyListBox.ItemTemplate>
</my:EmptyListBox>
person Steve Chadbourne    schedule 04.04.2011
comment
тоже не сработало - привязка работает, но похоже, что класс игнорирует тот факт, что я перегрузил ItemsSource в своем производном классе - person argh; 05.04.2011