我最近遇到了一個很奇怪的問題。如何在Windows Phone7中完全手動控制ListBoxItem的風格?
我想控制ListBoxItem自己渲染一個非常複雜的ListBox, 當我完成工作時,我發現第一個外觀正是我想要的,但是當我向下滾動ListBox時,我很困惑,沮喪地看到ListBoxItem的順序根本就沒有順序。
現在,我創建了一個新的空similiar項目和測試,結果是相同的(在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>
和パ中的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
感謝, 閃亮
是的,重新定義列表框的ItemsPanel可以解決這個問題,但會造成性能負擔。爲什麼V1的XAML沒有這個問題,V2的XAML有。兩者都具有UI虛擬化功能 – Sparkling
如果您的列表包含大量項目,那麼會導致性能問題。你也可以對自定義測試面板進行一些修改,爲你的DataProperty添加一個propertyChangedCallback,當你的面板被回收時,數據也會改變,你可以在回調中重建你的面板 – yiyang
我在上面的代碼中添加回調,但是它似乎列表框的外觀仍然無序。 – Sparkling