I was migrating my app from WP7 to WP8, and a funny thing is happening. I've a databound pivot who works perfectly in WP7. But, in WP8, the exact same code, doesn't load the first PivotItem. I've tried all the solutions in the question for WP7, none works (I want a solution, not an ugly workaround). I'm setting the DataContext in the constructor, the collection is OK, and everything should work. It only loads pivots when I scroll in the app. Anyone has any solution?
I can't repro any databinding issues with Pivot on WP8. There is a known issue with Panorama Databinding on WP8, but not Pivot. What exactly doesn't work for you?
Here's a basic WP8 Pivot Databinding code that works just fine for me.
C# code setting a DataContext to an observable collection of cows:
this.DataContext = new ObservableCollection<Cow>()
{
new Cow("Foo"),
new Cow("Bar"),
new Cow("Baz")
};
public class Cow
{
public Cow(string name)
{
Name = name;
}
public string Name { get; set; }
}
XAML code using that DataContext as the ItemSource and Binding PivotItem.Header and PivotItem.Content to the cow name.
<phone:Pivot ItemsSource="{Binding}">
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}" />
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}" />
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
Works just fine...
If it helps i had the same problem, did an ugly fix but it worked..
pivotTest.SelectedIndex = 1;
pivotTest.SelectedIndex = 0;
I created a repro of this bug here: https://github.com/michaellperry/PivotIsBroken
It appears that the bug occurs because the content animation is not triggered. The selected index is not actually changing.
The ugly workaround that I employed is similar to DavidN's recommendation, but I had to insert a dummy page. Setting SelectedIndex to 1 with only one page throws an exception.
Related
I have a Windows 8.1 application with a ListView and I am using ListViewExtensions from WinRt Xaml Toolkit(Obtained latest from Nuget) to bind BindableSelection
Here is my XAML
<ListView
ItemsSource="{Binding AllItems}"
SelectionMode="Multiple"
ext:ListViewExtensions.BindableSelection="{Binding SelectedItems, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In my ViewModel I have the following ObservableCollection which I have bound my xaml to
private ObservableCollection<string> _SelectedItems;
public ObservableCollection<string> SelectedItems
{
get { return _SelectedItems; }
set
{
if (value != _SelectedItems)
{
_SelectedItems = value;
NotifyPropertyChanged("SelectedItems");
}
}
}
I have put breakpoints on the get and set of my ObservableCollection. The get will be called as soon as my View loads, but the set is never called even though I select multiple items of my ListView.
Am I doing something wrong.
I would be very glad if someone can point me in the right direction.
Thanks in Advance.
Realized my mistake. I have never created the object for ObservableCollections SelectedItems.
One should create the object for the ObservableCollection at some point otherwise the XAML will be binding to a null object reference which obviously cannot be updated.
Here is how you instantiate the ObservableCollection.
SelectedItems = new ObservableCollection<MyItems>();
However I am still unable to hit the breakpoint of the set function of the ObservableCollection. I believe that this is the default behavior of the Observable. Would be glad if someone can comment on that.
Nevertheless the problem for this particular question is solved.
Thanks
Hi this should be faily simple, however I don't know what I am doing wrong. I've been looking all over the internet seeing people make this work, even followed the tutorial on MSDN still nothing has worked for me.
I want to Iterate over a ListBox, and get the ListBoxItems so I can find the DataTemplate that I have added to it.
This is my code behind.
private void SetListBoxDataTemplate(ListBox MyListBox)
{
try
{
foreach (CustomDataTemplateObject dataobject in MyListBox.Items)
{
ListBoxItem lbi = (ListBoxItem)(MyListBox.ItemContainerGenerator.ContainerFromItem(dataobject));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(lbi);
DataTemplate dt = myContentPresenter.ContentTemplate;
TextBlock tb = (TextBlock)dt.FindName("ListBoxItemTextBlock1", myContentPresenter);
ComboBox cb = (ComboBox)dt.FindName("ListBoxItemComboBox1", myContentPresenter);
tb.Text = dataobject.Text;
cb.ItemsSource = dataobject.ListColors;
}
}
catch (Exception ex)
{
MessageBox.Show(""+ex);
}
}
XAML looks like this:
<DataTemplate x:Key="ListBoxItemDataTemplate1">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Black" BorderThickness="1 1 0 1" MinWidth="50">
<TextBlock Name="ListBoxItemTextBlock1" Background="{Binding ElementName=ListBoxItemComboBox1, Path=SelectedValue}" >
</TextBlock>
</Border>
<ComboBox Name="ListBoxItemComboBox1" />
</StackPanel>
</DataTemplate>*
<StackPanel>
<ListBox Name="ListBoxTest1" ItemTemplate="{DynamicResource ListBoxItemDataTemplate1}" />
</StackPanel>
I have tried with setting my itemtemplate to static to see if it works, and the method i'm calling from code behind, is called after I have populated my ListBoxs
My dataobject is NOT null, however when i call the line in my code behind, my lbi, ends up being null.
Any suggestions? thanks in advance!
FIRST UPDATE
This problem only occurs if i call the method in my constructor, so perhaps it's because it hasn't initialized the full group element section yet. However I want to do this as soon as possible. Am I perhaps forced to do it in a WindowLoaded event?
SECOND UPDATE
Code updated, Rachel's answer worked for iterating over my ListBoxItems, however the Listbox Has not fully rendered since i'm unable to reach the Datatemplate at this time. So MyListBox_GeneratorStatusChanged is not working for this problem, but it does get the ListBoxItems.
WPF's main thread runs items at different priority levels. Code that runs in the Constructor all gets run at Normal priority, while things like rendering the ListBox and it's items run at the Render priority level, which occurs after all Normal priority operations have finished.
This means that your entire Constructor gets run (including SetListBoxDataTemplate()) before your ListBox is even rendered and the items get generated.
If you want to run some code after the items are generated, use the ItemsContainerGenerator.StatusChanged event
// Constructor
MyListBox.ItemContainerGenerator.StatusChanged += MyListBox_GeneratorStatusChanged;
...
void MyListBox_GeneratorStatusChanged(object sender, EventArgs e)
{
// return if containers have not been generated yet
if (MyListBox.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
return;
// remove event
MyListBox.ItemContainerGenerator.StatusChanged -= MyListBox_GeneratorStatusChanged;
// your items are now generated
SetListBoxDataTemplate(MyListBox);
}
What are you trying to accomplish with this method anyways? It is a bit unusual for WPF, and there may be a much better WPF way of accomplishing your task.
Updated based on new code added to Question
A much better method of setting your Text and ItemsSource properties is to make use of WPF's data bindings.
Your DataTemplate should look like this:
<DataTemplate x:Key="ListBoxItemDataTemplate1">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Black" BorderThickness="1 1 0 1" MinWidth="50">
<TextBlock Text="{Binding Text}" Background="{Binding ElementName=ListBoxItemComboBox1, Path=SelectedValue}" >
</TextBlock>
</Border>
<ComboBox ItemsSource="{Binding ListColors}" />
</StackPanel>
</DataTemplate>*
A DataTemplate is like a cookie cutter. It's used to make the UI objects, but is not part of the UI object itself. All it does is tell WPF that "When you go to render this object, render it using this XAML". So the way your XAML gets rendered is
<ListBoxItem>
<StackPanel>
<Border>
<TextBlock Text="{Binding Text}" />
</Border>
<ComboBox ItemsSource="{Binding ListColors}">
</StackPanel>
</ListBoxItem>
In addition, the DataContext behind your ListBoxItem is the item from the collection bound to ListBox.ItemsSource, which based on your code should be CustomDataTemplateObject. That allows the bindings from the DataTemplate to work
If you're new to WPF and struggling to understand how exact the DataContext works, I'd recommend reading this article of mine: What is this "DataContext" you speak of?.
To summarize, WPF has two layers to an application: the UI layer and the Data Layer (DataContext). When you perform a basic binding like above, you are pulling data from the data layer into the UI layer.
So your ListBoxItem has a data layer of CustomDataTemplateObject, and the TextBlock.Text and ComboBox.ItemsSource bindings are pulling data from the data layer for use in the UI layer.
I'd also highly recommend using a utility like Snoop which lets you view the entire Visual Tree of a running WPF application to see how items get rendered. Its very useful for debugging or learning more about how WPF works.
You're confusing two jobs and mixing them into one. First, get access to the ListBoxItem:
private void SetListBoxDataTemplate(ListBox MyListBox)
{
foreach (ListBoxItem listBoxItem in MyListBox.Items)
{
}
}
Now you can get the DataTemplate from the ListBoxItem:
foreach (ListBoxItem listBoxItem in MyListBox.Items)
{
ContentPresenter presenter = FindVisualChild<ContentPresenter>(listBoxItem);
DataTemplate dataTemplate = presenter.ContentTemplate;
if (dataTemplate != null)
{
// Do something with dataTemplate here
}
}
The FindVisualChild method can be found in the How to: Find DataTemplate-Generated Elements page on MSDN.
UPDATE >>>
To answer your edit, yes, the constructor will be too early to try to access these DataTemplates because the Framework won't have applied them to all of the objects by then. It is best to use the FrameworkElement.Loaded Event to do these kinds of things, as that is the first event that can be called after the controls have all been initialised.
I'm in a bit of a bind here (no pun intended); I have a large collection of view models (500+) which are displayed using an ItemsControl with a WrapPanel as the ItemsPanelTemplate. Each of these view models exposes a Boolean? whose value is bound to the IsChecked property of a CheckBox on the user interface.
The problem is this... whenever I attempt to update all the checkboxes at once it is horrendously slow. Almost 10 seconds to update a list of 500 items. If I run the updating code in a seperate thread I can almost watch the checkboxes be updated one by one.
Can anyone enlighten me as to why this process is so slow and how I could improve it?
I have considered that perhaps the non-virtualizing nature of the WrapPanel could be the guilty party. However, when I bind to the IsEnabled property instead of IsChecked I see an interesting result; namely that changing the value of IsEnabled to true is slow as expected, but changing to false happens instantaneously. This makes me suspicious that the checkbox animation is at fault because as far as I can tell visually there is no animation when disabling a checkbox, but there is when enabling. Profiling has revealed that the vast majority of time is spent in the PropertyChangedEventManager.OnPropertyChanged() method.
Example code below, I'm unfortunately forced to use .NET 3.5:
XAML:
<ItemsControl ItemsSource="{Binding ChildItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type SampleViewModel}">
<CheckBox IsThreeState="True" IsChecked="{Binding Path=IncludeInPrinting, Mode=OneWay}" />
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
ViewModel:
public class SampleViewModel : INotifyPropertyChanged
{
private Boolean? _includeInPrinting;
public Boolean? IncludeInPrinting
{
get
{
return _includeInPrinting;
}
set
{
if (_includeInPrinting != value)
{
_includeInPrinting = value;
RaisePropertyChanged(() => IncludeInPrinting);
}
}
}
}
Slow Code:
foreach (SampleViewModel model in ChildItems)
{
model.IncludeInPrinting = false;
}
EDIT: For what it's worth I'm also seeing a spike in memory usage whenever I check all or uncheck all the checkboxes. ~10MB
EDIT: The performance analysis below seems to confirm that animation is definitely the issue.
I would look at the following control which is open source on CodePlex..
http://virtualwrappanel.codeplex.com/ (Note: I have no affilication with Virtualizing Wrap Panel)
Due to the large number of view models you are working with this would drastically improve performance for you.
Well, well, this is my very first question in StackOverflow! I've been using this site since ages but I never had to ask something because I always found the answer in someone else's question lol Apparently this is not the case anymore lol.
Anyway, I'm trying to bind a list of a custom class (that is decorated to be used with the DataContext that manages a local SQL Server CE 3.5 database - natively included in Windows Phone 7.5) to a ListPicker control from the WPToolkit and strangely I can't see the value of the element I bound in the ListPicker (I made sure the list is populated).
Here's the class:
[Table(Name = "Rubriques")]
class Rubrique
{
[Column(IsPrimaryKey = true, DbType = "TINYINT", CanBeNull = false)]
public Byte Id { get; set; }
[Column(DbType = "NVARCHAR(40)")]
public String Nom { get; set; }
}
Here's the DataContext:
class IntermediaireDataContext : DataContext
{
public IntermediaireDataContext() : base("Data Source='isostore:/IntermediaireBDD.sdf';")
{
}
public Table<Rubrique> Rubriques
{
get { return this.GetTable<Rubrique>(); }
}
}
Here's the code I use to bind the list to the ListPicker:
using (IntermediaireDataContext context = new IntermediaireDataContext())
{
rubs = (from x in context.Rubriques select x).ToList<Rubrique>(); //rubs already exists
RubListPicker.ItemsSource = rubs;
}
Here's the XAML:
<toolkit:ListPicker x:Name="RubListPicker" SelectionMode="Single" FullModeHeader="Rubriques">
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Nom}" FontSize="16"/>
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
<toolkit:ListPicker.FullModeItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Nom}" FontSize="26" FontWeight="Bold"/>
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.FullModeItemTemplate>
</toolkit:ListPicker>
The list of Rubrique rubs gets populated and is set as ItemsSource to RubListPicker and if I remove the Text="{Binding Nom}" of the TextBlock in the DataTemplate I can see the name of the class MyNamespace.Rubrique in every element in the ListPicker.
I can't figure out what is the problem with the data binding... Any help would be greatly appreciated :)
I'm using the last version of WPToolkit 4.2012.10.30 from NuGet in Visual Studio 2012 Ultimate with the Windows Phone 8 SDK.
Thanks for taking the time to read this!
Regards,
Ali
EDIT
I found the solution and it made me laugh hard lol.
I had to change de security level of my class Rubrique; When I did set it to public everything worked fine.
Actually, the ListPicker had access to the List<Rubrique> but could not access the value of each Rubrique.
A good one to remember for the future: Always check the security level of your classes/attributes/methods when using external libraries.
This is my first question ever in StackOverflow and I get to answer it myself: Like A Boss :D
So the trick was to make my class public so it can be accessed by the ListPicker control from WPToolkit ;)
Cheers!
I'm having a problem with the autocompletebox from the toolkit for windows phone. I bind it to some data, then when i press it and start typing, it discovers some items but they are displayed wrong (the list is shown separated from the box, and also if i click on any item, nothing happens. If i click where the item would be supposed to be (for example, right on the top of the box), then it gets selected. It looks like a rendering problem (bug?)) but perhaps i'm doing something wrong. Here's the code for the box :
<DataTemplate x:Key="DataTemplate1">
<ContentControl Content="{Binding Name}" Margin="8,7"/>
</DataTemplate>
<toolkit:AutoCompleteBox ItemsSource="{Binding}" x:Name="txtSelectValues" MinWidth="250" Margin="0,0,0,0" ItemTemplate="{StaticResource DataTemplate1}" VerticalAlignment="Top" />
Found it. It's a bug with the AutoCompleteBox. When inside a scrollviewer control, the dropdown gets messed up and displayed in an incorrect position
Its not just that is also to do with being placed inside of a Pivot/Panaroma as well as the scrollviewer, the silverlight gurus have stated they haven't a timeline for the fix for the Pivot control, and there is a nasty hack
http://silverlight.codeplex.com/workitem/7574
I think the answer might just be that you shouldn't be using a ContentControl directly used like this. Try using something like a TextBlock instead - e.g.:
<DataTemplate x:Key="DataTemplate1">
<TextBlock Text="{Binding Name}" Margin="8,7"/>
</DataTemplate>
If that's not the answer, then try pulling back to a simple example - especially removing all the Margin's, Width's, Alignment's, etc - then put them back in one-by-one to work out and understand what is causing the effect you are seeing.