Strange artifact when updating Pivot title in Windows Phone 8 - c#

I have a XAML page with just a Pivot with binded ItemSource and the following template (changing just the header for simpilcity)
<phone:Pivot
Margin="0,108,0,0"
ItemsSource="{Binding Services}">
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
The ItemSource (Services) is an ObservableCollection of a simple data type with just a Title property implementing INotifyPropertyChanged. When I change the Title of any item, the Pivot header is rendered very strangely:
Here is a complete simplified solution to reproduce the problem: https://dl.dropboxusercontent.com/u/73642/pivotproblem.zip
Is this a Pivot bug?

Indeed a bug... I had the same problem and I end up in forcing to reload whole DataContext of the Pivot.
Since I was using MVVM I just created new instance of the items collection and raised property changed for that.

It seems that TextBlock's Width is not updated after Title changes. You can check it by defining your TextBlock like this:
<TextBlock Text="{Binding Title}" Width="400" />
Hence it's not updated, two Titles overlap each other.

Related

Nesting databound controls inside a WPF TreeView

Trying to build a WPF TreeView control which can contain another data bound control inside it. Here's the XAML:
<TreeView temsSource="{Binding DocumentCategories}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding DocumentCategory1}">
<TextBlock FontWeight="Bold" Text="{Binding Description}"></TextBlock>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Documents}">
<TextBlock FontWeight="Bold" Text="{Binding Name}"></TextBlock>
</ListView>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
The DocumentCategories data is recursive - each item in the list has a DocumentCategory1 collection of DocumentCategories which has its own DocumentCategory1 collection and so forth.
Without the ListView inside it, this works just fine. However, when you add the ListView the TreeView renders ok but when you try and open one of the nodes, the application crashes with the error:
Operation is not valid while ItemsSource is in use. Access and modify
elements with ItemsControl.ItemsSource instead
I'm not entirely sure which ItemsSource this is referring to - that of the TreeView or the ListView. I presume the latter, and that the problem is being caused by the fact that the binding isn't actually happening until after the node is opened.
I've tried changing both DocumentCateegories and Documents from List to an ObservableCollection, which seems to be a common fix for this error - but it still behaves the same.
Is it possible to have another databound control inside a TreeView, and if so, how?
There is the DataTemplate of the ListView missing.
Currently the following Element is interpreted as an actual ListView Element:
<TextBlock FontWeight="Bold" Text="{Binding Name}"></TextBlock>
And as you already bound the ListView's ItemSource the error occurs, when the view is trying to add the "TextBlock" as an item of the ListView.
Just change it to the following:
<ListView ItemsSource="{Binding Documents}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Display data from two levels down

I have the following classes, which contain ObservableCollections of the next level down:
Draw
ObservableCollection<Round>();
Round
ObservableCollection<Formation>();
Formation
So a Draw is made up of Rounds, Rounds are made up of Formations.
I have a page which has a button to create a random draw, I currently have it calling another class which returns a draw:
this.defaultViewModel[DrawName] = RandomDraw.generate();
I am having no problem binding a ListView to Rounds and displaying round information, but how do I display the individual formations? This is what I am currently doing, I was not expecting to be able to just display things by binding to Formations but how do I access it?
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<TextBlock
Text="{Binding Formations}"
TextWrapping="WrapWholeWords"
Pivot.SlideInAnimationGroup="2"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemContentTextBlockStyle}"
Margin="0,0,19,0"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You should take a look at Hierarchical Data Templates, which are used by the WPF TreeView control rather than ListViews. They are a natural fit to show hierarchical data. Of course, like any WPF control, you can completely customize their appearance using styling and templates. Here are some good references:
MSDN How to: Use a TreeView to Display Hierarchical Data
Hierarchical Databinding in WPF
However, if you would like to keep using ListViews, then one way to do this is to nest another container control inside the parent ListVIew. ObservableCollections are processed automatically by specific WPF elements, such as Panels. In your example, you can replace the second TextBlock with another ListView, with an ItemTemplate similar to the first. It can also be any Collection-like Panel element, such as StackPanel.
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<!-- CHANGED CODE HERE -->
<ListView
ItemsSource="{Binding Formations}"
...>
<ListView.ItemTemplate>...</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

C# WPF Binding to DataBase

Hei all. If something would be not clear then please tell
I have dataGrid and TreeView.
I have loaded data base as Entity Data Model and some tables.
One of these tables "relation" should show to the datagrid. But its (relation table) column depend of the other tables as system,model,function and device. In the Data grid should be 4 columns which contain names of these system,model,function and device. (the picture 1 as should be)
Problem in the how it all show. DataSource don't work well... see picture 2.
<Grid DataContext="{StaticResource relationsViewSource}">
<DataGrid AutoGenerateColumns="True" Name="gridInventory" HorizontalContentAlignment="Right" Margin="255,12,12,128" ItemsSource="{Binding}" />
<StackPanel Height="391" HorizontalAlignment="Left" Margin="10,10,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="239" DataContext="{StaticResource systemsViewSource}" >
<TreeView Height="391" Name="treeView1" Width="239" VerticalContentAlignment="Top" HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding}" />
</StackPanel>
</Grid>
Picture 1:
Picture2:
You are binding both the TreeView and some of your DataGrid columns to an object, but not telling WPF how to draw the object. When WPF doesn't know how to draw an object, it by default draws it using a TextBlock with the Text bound to the object's .ToString()
You need to set the ItemTemplate to tell WPF how to draw your individual objects, such as this:
<TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TreeView.ItemTemplate>
You could also use an implicit DataTemplate to tell WPF how to draw specific objects. This is just a DataTemplate that specifies a DataType without a Key, and WPF will use it anytime it tries to render an object of the specified type.
If you want to avoid removing AutoGenerateColumns="True" and manually specifying your DataGrid's columns, this is probably the method to use.
<DataGrid.Resources>
<DataTemplate DataType="{x:Type local:Device}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</DataGrid.Resources>
The TreeView you would need to set the Path on the Binding to the property you want to display,
The Devices is a collection and you need to put a Listview in there or something that will display a collection and then put a DataTemplate on it to display what you need, either that or bind to a converter to return a static string representation of the Device list
Or just get someone to do it all for you as seems the case on here lol

Optimal way to populate a large number of textboxes in MVVM

I'm currently creating a WPF application using MVVM. I have a large number of textboxes in a window (about 20) that need to be bound to specific elements in a list and need to be populated all at once. Normally I'd push them into an array and populate them that way but I can't do so without breaking the MVVM model. Is there a quick and efficient way I can do this while still adhering to MVVM?
You could bind your list to an ItemsControl and change it's item template to be a TextBox.
<ItemsControl ItemSource={Binding aList}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I don't see why strictly this would break MVVM, if instead of using an Array you used a List, put it in your ViewModel and then use indexed binding to bind to specific elements.
Something like:
<StackPanel>
<TextBox Text="{Binding MyViewModelList[0]}">
<TextBox Text="{Binding MyViewModelList[1]}">
<TextBox Text="{Binding MyViewModelList[2]}">
</StackPanel>
or if you want something more dynamic, instead of List, put an ObservableCollection in your VM, and bind to it in an ItemsControl with a DataTemplate.
<ItemsControl ItemsSource="{Binding Path=MyViewModelObsCol}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Syntax might not be 100% as I don't have an IDE to test, but something along these lines might be what you're after.
If you are trying to populate textbox on the bases of selection in list box try this
Another option is creating a COllection view source which i don't think you will require here

Display properties of the ListBox.ItemsSource

I am new to WPF. I have a ListBox that has its ItemSource set to a instance of WorkItemCollection. (A collection of WorkItem objects.)
When the list is displayed it only displays the type of each object (Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem). Is there a way to make the list display WorkItem.Title?
You have two options.
The simplest method is to set the DisplayMemberPath property of your ListBox to "Title".
If you want to set not only what gets displayed, but the type of control that is used to display it, then you would set the ListBox's ItemTemplate.
For what your goal is, I would recommend the first option.
You can set a DataTemplate on the ItemTemplate property of the ListBox:
<ListBox ItemSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate DataType="tfs:WorkItem">
<StackPanel>
<TextBlock Text="{Binding Title}" />
<!-- Others -->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Categories