Как вручную полностью управлять стилем ListBoxItem в Windows Phone7? - PullRequest
0 голосов
/ 27 октября 2011

Недавно я столкнулся с очень странной проблемой.

Я хочу сам управлять рендером ListBoxItem для очень сложного ListBox, Когда я закончил работу, я обнаружил, что первое появление - это именно то, что я хочу, но когда я прокрутил ListBox вниз, я был смущен и расстроен, увидев, что порядок ListBoxItem не в порядке.

Теперь я создал новый пустой подобный проект и протестировал, результат тот же. (В Windows Phone 7 есть, Но в приложении WPF все хорошо.)

V1

<ListBox x:Name="ListBoxTest">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Channel}" Width="1000"></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

V1 просто привязывает свойство к специальному элементу управления, таким образом, все хорошо. и вещи разные в V2:

<ListBox x:Name="ListBoxTest">
<ListBox.ItemTemplate>
    <DataTemplate>
        <local:TestPanel Data="{Binding}"  HoldedHeight="100"></local:TestPanel>
    </DataTemplate>
</ListBox.ItemTemplate>

и TestPanel в DataTemplate:

public class TestPanel : StackPanel
{
    private bool _beginLoaded;
    private bool _isLoaded;
    private ListBox _parentListBox;

    public TestPanel()
        : base()
    {
        this.Loaded += TestPanel_Loaded;
    }

    void TestPanel_Loaded(object sender, RoutedEventArgs e)
    {
        if (Data != null)
        {
            System.Diagnostics.Debug.WriteLine("ProgramsPanel_Loaded with {0}", Data.Channel);
        }
        else
        {
            System.Diagnostics.Debug.WriteLine("ProgramsPanel_Loaded with NULL data");
        }

        if (_beginLoaded || _isLoaded)
            return;

        _beginLoaded = true;
        InitializeWidthParent();
        this.Children.Clear();
        Show(Data, HoldedWidth, HoldedHeight);
        _isLoaded = true;
    }




    private void InitializeWidthParent()
    {
        _parentListBox = FindParent<listbox>(this);
        if (_parentListBox != null)
        {
            HoldedWidth = _parentListBox.ActualWidth;               
        }
    }

    static T FindParent<t>(DependencyObject d) where T : DependencyObject
    {
        DependencyObject parent = d;
        while (parent != null)
        {
            parent = VisualTreeHelper.GetParent(parent);
            if (parent != null && (parent.GetType() == typeof(T)))
            {
                return parent as T;
            }
        }
        return parent as T;
    }

    private void Show(TestDataItem data, double holdedwidth, double holdedheight)
    {

        if (data == null)
            return;

        if (!holdedwidth.IsValid() || !holdedheight.IsValid())
            return;

        #region Stand at Left Side (Channel Name and Image)
                    System.Diagnostics.Debug.WriteLine("Begin Show this Pannel of {0}", data.Channel);

        TextBlock tb = new TextBlock() { FontSize = 32,  Height=HoldedHeight,Text = data.Channel, HorizontalAlignment = HorizontalAlignment.Center };


        this.Children.Add(tb);
        #endregion

        #region Right Side


        #endregion
    }

    public double HoldedWidth
    {
        get;
        set;
    }

    public double HoldedHeight
    {
        get;
        set;
    }



    /// <summary>
    /// The <see cref="Data" /> dependency property's name.
    /// </summary>
    public const string DataPropertyName = "Data";

    /// <summary>
    /// Gets or sets the value of the <see cref="Data" />
    /// property. This is a dependency property.
    /// </summary>
    public TestDataItem Data
    {
        get
        {
            return (TestDataItem)GetValue(DataProperty);
        }
        set
        {
            SetValue(DataProperty, value);
        }
    }

    /// <summary>
    /// Identifies the <see cref="Data" /> dependency property.
    /// </summary>
    public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
        DataPropertyName,
        typeof(TestDataItem),
        typeof(TestPanel),
        new PropertyMetadata(null, OnDataPropertyChanged));

    private static void OnDataPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as TestPanel).OnDataPropertyChanged(e.OldValue as TestDataItem, e.NewValue as TestDataItem);
    }

    protected virtual void **OnDataPropertyChanged**(TestDataItem oldData, TestDataItem newData)
    {
        if (oldData != null)
        {
            Show(oldData, HoldedWidth, HoldedHeight);
            System.Diagnostics.Debug.WriteLine("rebuild old pannel of {0}, ListBox count is {1}", oldData.Channel, _parentListBox.Items.Count);
        }

        string oldstr = oldData == null ? "NULL" : oldData.Channel;
        string newstr = newData == null ? "NULL" : newData.Channel;

        System.Diagnostics.Debug.WriteLine("old data is {0}, new data is {1}", oldstr, newstr);
    }
}


public static partial class Extentsions
{
    public static bool IsValid(this double width)
    {
        if (double.IsNaN(width)
            || Math.Abs(width) < 0.1)
        {
            return false;
        }

        return true;
    }
}


public class TestDataItem
{
    public string Channel
    {
        get;
        set;
    }

}

главная страница:

public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();

        this.Loaded += new RoutedEventHandler(MainPage_Loaded);         
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        ObservableCollection<testdataitem> source = new ObservableCollection<testdataitem>();
        ListBoxTest.ItemsSource = source;

        for (int i = 0; i < 10; i++)
        {
            source.Add(new TestDataItem() { Channel = i.ToString() });
        }
    }
}

так почему после использования V2 элементы ListBoxItems будут появляться беспорядочно, и как я могу решить эту проблему?

PS: выходная информация:

old data is NULL, new data is 0

old data is NULL, new data is 1

old data is NULL, new data is 2

old data is NULL, new data is 3

old data is NULL, new data is 4

old data is NULL, new data is 5

old data is NULL, new data is 6

old data is NULL, new data is 7

old data is NULL, new data is 8

old data is NULL, new data is 9

ProgramsPanel_Loaded with 0

Begin Show this Pannel of 0

ProgramsPanel_Loaded with 1

Begin Show this Pannel of 1

ProgramsPanel_Loaded with 2

Begin Show this Pannel of 2

ProgramsPanel_Loaded with 3

Begin Show this Pannel of 3

ProgramsPanel_Loaded with 4

Begin Show this Pannel of 4

ProgramsPanel_Loaded with 5

Begin Show this Pannel of 5

ProgramsPanel_Loaded with 6

Begin Show this Pannel of 6

ProgramsPanel_Loaded with 7

Begin Show this Pannel of 7

ProgramsPanel_Loaded with 8

Begin Show this Pannel of 8

ProgramsPanel_Loaded with 9

Begin Show this Pannel of 9

Begin Show this Pannel of 9

rebuild old pannel of 9, ListBox count is 10

old data is 9, new data is 0

ProgramsPanel_Loaded with 8

Спасибо, Игристое

1 Ответ

0 голосов
/ 27 октября 2011

Я полагаю, что проблема вызвана "особенностью" списка: Виртуализация пользовательского интерфейса .Проще говоря, виртуализация пользовательского интерфейса поможет вам уменьшить память пользовательского интерфейса и отображать только элементы, видимые на экране.Таким образом, ваша пользовательская тестовая панель будет переработана и повторно использована при прокрутке списка.Может быть, я не очищен, но вы можете просто попытаться отключить функцию виртуализации пользовательского интерфейса списка, используя стекпанель в качестве ItemPanel ListBox, чтобы увидеть, если ваша проблема решена.:

<ListBox>
  <ListBox.ItemsPanel>
     <ItemsPanelTemplate>
         <StackPanel/>
     </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
</ListBox>

Кроме того, вы можете добавить propertychangedCallback к свойству Data и перестроить элемент панели в этом обратном вызове.Это вызовет, когда ваша панель будет переработана, и ее данные будут изменены.

/// <summary>
/// Identifies the <see cref="Data" /> dependency property.
/// </summary>
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
    DataPropertyName,
    typeof(TestDataItem),
    typeof(TestPanel),
    new PropertyMetadata(null, OnIsDataChanged));

protected static void OnIsDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        //rebuild your panel here......

        this.Children.Clear();
        Show(Data, HoldedWidth, HoldedHeight);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...