Недавно я столкнулся с очень странной проблемой.
Я хочу сам управлять рендером 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
Спасибо,
Игристое