ContentControl and CollectionView.CurrentItem - c#

Referencing this example:
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-bind-to-a-collection-and-display-information-based-on-selection
(some relevant code snippets:)
<Window.Resources>
<local:People x:Key="MyFriends"></local:People>
<DataTemplate x:Key="DetailTemplate">
<Border Width="300" Height="100" Margin="20"
BorderBrush="Aqua" BorderThickness="1" Padding="8">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="First Name:"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=FirstName}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Last Name:"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=LastName}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Home Town:"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=HomeTown}"/>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<ListBox Width="200" IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource MyFriends}}"/>
<ContentControl x:Name="contentControl1"
Content="{Binding Source={StaticResource MyFriends}}"
ContentTemplate="{StaticResource DetailTemplate}" />
Both ListBox.ItemsSource and ContentControl.Content bind to the same source (MyFriends, an instance of the People class which derives from ObservableCollection<Person>). If my understanding is correct, this means that both the ListBox.ItemsSource and ContentControl.Content properties will be bound to the same implicitly created instance of ListCollectionView.
I understand that setting ListBox.IsSynchronizedWithCurrentItem="True" synchronizes ListBox.SelectedItem and ItemCollection.CurrentItem.
DetailTemplate (above) displays the details of the selected ListBox item, despite being 'bound' to a ListCollectionView. Specifying Path=/ (what I thought would be necessary to achieve the resulting behavior) does not have any effect - it's as if WPF knows to do it implicitly somehow:
<ContentControl x:Name="contentControl1"
Content="{Binding Source={StaticResource MyFriends}, Path=/}"
ContentTemplate="{StaticResource DetailTemplate}" />
As a test, I created another ContentControl with Content bound to a DataTemplate containing a ListBox:
<ContentControl x:Name="contentControl2"
Content="{Binding Source={StaticResource MyFriends}}"
ContentTemplate="{StaticResource DetailTemplate2}" />
<DataTemplate x:Key="DetailTemplate2">
<ListBox ItemsSource="{Binding}"></>
</DataTemplate>
And it displayed the list.
My question is: Why does DataTemplate get the selected Person object while the ListBox and DetailTemplate2 get the People collection?
(the behavior is desirable, I just don't understand what black magic is occurring under the hood to make it so)

Is a good question! I didn't notice that until read your post. So, after did some digging from source code of PropertyPathWorker, it appears that when PropertyPathWorker failed to solve a member of an object, in your case, it try to solve 'FirstName', 'LastName' ect. with 'MyFriends', it will try to solve it with the view of the object. And if still failed, it will try to solve it with view's CurrentItem, and that's where the magic happened. You can find those codes in PropertyPathWorker.UpdateSourceValueState(int k, ICollectionView collectionView, object newValue, bool isASubPropertyChange) and PropertyPathWorker.ReplaceItem(int k, object newO, object parent).

Related

WPF TreeView Indentation is missing

I have a TreeView which is binded to a OberservableCollection. When I add Items to that List everything works, except that the indentation of the TreeView is missing. All TreeViewItems have the same level of indentation, regardless of their level insinde the treeview. The problem with that is that you can't really see which element is at which level.
The Item class contains a list of other Items called "Children", a string called "ItemName" and a BitmapImage called "ImageSource".
I already tried it without bindings. I simply added new TreeViewItems on events, but I had the same problem with that.
Here is my XAML Code for that TreeView:
<TreeView Grid.Column="0" Name="ProjectTree" ItemsSource="{Binding ItemList, Mode=TwoWay}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type ViewItems:Item}" ItemsSource="{Binding Path=Children, Mode=TwoWay}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding ImageSource}" RenderOptions.BitmapScalingMode="HighQuality" Grid.Column="0" Width="20" Margin="1"/>
<TextBlock Text="{Binding ItemName}" Grid.Column="1" VerticalAlignment="Center"/>
</Grid>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
The bindings are fine, as I said. It is only the indentation that doesn't work.
I'd be glad if you people could help me.

Get Values inside an ItemTemplate of a ListView C#

<ListView Name="myList" Background="Transparent" Margin="15,88,15,15">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="5">
<TextBlock Name="xName" Text="{Binding Name}" FontSize="30" Margin="10,0,5,0" FontWeight="Medium"/>
<TextBlock Name="xNo" Text="{Binding No}" FontSize="25" Margin="10,0,5,0" TextTrimming="CharacterEllipsis"/>
</StackPanel>
<Grid Grid.Column="1" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<RadioButton Grid.Column="0" Name="r1" Content="1" Width="10" Margin="5,15,-2,5"/>
<RadioButton Grid.Column="1" Name="r2" Content="2" Width="10" Margin="5,15,-2,5"/>
</Grid>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now I want to retrieve each item in ListView i.e, the controls in it. The TextBlocks content and to know which RadioButton is selected.
I tried taking classes like this
public class Att
{
public string Name;
public string No;
public RadioButton r1;
public RadioButton r2;
}
There are separate sources for the content of the TextBoxes in the ListView. They come from different classes. I tried retrieving the items using above class Att.
But it is showing some type conversion errors. Please anyone help me! I'm a beginner.
Thanks is advance.
Thanks for all the support!
Well I tried doing this on my own and finally I got it. What I really wanted is to know which RadioButton is checked. I tried taking class Att for retrieving the items in ListView. I made modifications to the Att Class and added properties r1 and r2 of type bool instead of RadioButton and binded this property to the IsChecked property of the RadioButton in XAML and also mode of binding is TwoWay. So the changes done in the XAML can be reflected in the source list of items.

WPF Bind to object (non static) method

I'm trying to bind to an instance method of an object but I can only find examples to bind to properties or static methods. Here's the relevant part of my code:
<Window.Resources>
<ObjectDataProvider x:Key="identifier" MethodName="getIdentifier" ObjectType="{x:Type self:PartModel}" />
</Window.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding identifier}" Grid.Column="0" />
<TextBlock Text="{Binding Title}" Grid.Column="1" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
PartModel is an object that I use for filling the ItemsControl. The Title shows up and the getIdentifier method works when I call it in my regular code. But in my View only the title shows and the column for the identifier remains empty.
Is this even possible or do I have to write the identifier to a property of the model?
You are currently binding to an identifier property, which does not exist on the DataContext object of your list items.
Set the binding Source object instead, to the ObjectDataProvider resource that is references by the identifier resource key:
<TextBlock Text="{Binding Source={StaticResource identifier}}"/>

Custom ListView from inside HubAppSection -- Windows Phone 8.1

I am currently building a Windows Phone Applicaation, based off of the HubAppTemplate.
The template comes with a sample .JSON data source that it uses to populate the data of each HubSection. However, I want to use a non JSON type of data as the basis of my code. Inside my C# code, I need to make a function call to my backend to get the type of data I want out of it.
I can put this data inside of my own custom list (on the C# side), but how can I make that list act as the data source for my HubSection? Any old listview/list box works perfectly. Basically, I need help wiring the C# to the XAML -- the main issue is that I cannot access my listView inside of the datatemplate by name.
Can anyone give me some pointers to get going in the right direction?
Here is some reference code to show you what I am talking about:
<HubSection x:Uid="Clubs" Header="Clubs" DataContext="{Binding Groups}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}">
<DataTemplate>
<ListView Name="ClubsList"
IsItemClickEnabled="True"
ItemsSource="{Binding}"
ItemClick="GroupSection_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,27.5">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</HubSection>
The above XAML is basically pulled straight from the hubapp template. I want to be able to use my own itemssource inside of that ListView that is generated from my C# code -- however, I cannot figure out how this ItemsSource works. I also cannot access my listview by name (ClubsList).
Here is the initialization code going on up top (wasn't sure if it was important to post this or not):
<Page
x:Class="HubAppTemplate.HubPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HubAppTemplate"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:HubAppTemplate.Data"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
d:DataContext="{Binding Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="HubSectionHeaderTemplate">
<TextBlock Margin="0,0,0,-9.5" Text="{Binding}"/>
</DataTemplate>
<!-- Grid-appropriate item template as seen in section 2 -->
<DataTemplate x:Key="Standard200x180TileItemTemplate">
<Grid Margin="0,0,9.5,9.5" Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="138.5" Width="138.5"/>
<TextBlock Text="{Binding Title}" VerticalAlignment="Bottom" Margin="9.5,0,0,6.5" Style="{ThemeResource BaseTextBlockStyle}"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="StandardTripleLineItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,9.5,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}"/>
<TextBlock Text="{Binding Description}" Style="{ThemeResource ListViewItemContentTextBlockStyle}" Foreground="{ThemeResource PhoneMidBrush}" />
<TextBlock Text="{Binding Subtitle}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="StandardDoubleLineItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,9.5,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}"/>
<TextBlock Text="{Binding Subtitle}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid x:Name="LayoutRoot">
<Hub x:Name="Hub" x:Uid="Hub" Header="Club Alert" Background="{ThemeResource HubBackgroundImageBrush}">
It is pulling from the JSON backend, but I want to just use my own custom listview for each section. Deleting the DataSource and data template headers gives me errors, however.
Thank you so much for your help in advance!
--A total newbie
HubSection elements require their contents to be populated via a template, so you can't just remove the <DataTemplate> tags, unfortunately. However, there is a simple way to accomplish what you are trying to do, if I understand you correctly.
If you're starting with the default Hub template, you should have this function in your HubPage.xaml.cs file
private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var sampleDataGroups = await SampleDataSource.GetGroupsAsync();
this.DefaultViewModel["Groups"] = sampleDataGroups;
MainViewModel viewModel = DataContext as MainViewModel;
if (!viewModel.IsDataLoaded)
{
viewModel.Load();
}
}
this.DefaultViewModel is just a Dictionary, and they have loaded the sample JSON into a variable and stored this in the ["Groups"] key of the dictionary. Since the Page's DataContext is being bound to {Binding DefaultViewModel, RelativeSource={RelativeSource Self}}, the HubSection's DataContext is being bound to {Binding Groups}, and the ItemsSource of the ListView in each DataTemplate is being bound to {Binding}, each element of the loaded JSON is being used to fill the items of the ListView.
A simple solution would be to assign this.DefaultViewModel["Groups"] to the C# List you are creating from the data you load from your back end.
Something like this:
private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var myData = await GetListOfThingsFromBackend();
this.DefaultViewModel["Groups"] = myData;
MainViewModel viewModel = DataContext as MainViewModel;
if (!viewModel.IsDataLoaded)
{
viewModel.Load();
}
}
A better approach would probably be to separate out all ViewModel functionality to it's own class that is better suited to your needs, and then adjust the various DataContext properties throughout the XAML, but that would likely take more time. I can elaborate if needed, but the simple solution is probably enough for now.

Layout of list with different elements type in WPF

I need to fix a list with elements that have different types. Each of the type has it's own datatype to represent the viewmodel for each type. The following code works for me, but for some reason the data inside gets truncated, to some value (looks like default). I need to remove this trancation.
Here is what I have. This code is in the control, that could be placed in a list as well (it could be doubled or tripled). But I Don't think it's relevant.
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ListView DockPanel.Dock="Top" Name="testCaseResultListView"
ItemsSource="{Binding LogItems}"
ItemContainerStyleSelector="{StaticResource fixSideViewLogItemStyleSelector}"
SelectionMode="Single"
>
<ListView.View>
<GridView x:Name="gridView2">
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn CellTemplateSelector="{StaticResource fixSideViewLogItemTemplateSelector}"/>
</GridView>
</ListView.View>
</ListView>
</ScrollViewer>
</DockPanel>
fixSideViewLogItemTemplateSelector and fixSideViewLogItemStyleSelector are the selectors, that return different datatypes or styles for each of the type in LogItems. The common datatype is a grid with two columns, but that also seems irrelevent - I tried to put a textbox there, and it still gets truncated.
I would like this column to be stretched to the whole gridView. When I set width, of the column, I see the column resizing, but I want it to occupy the whole space. This should be elastic - if I put one control in the window, it should occupy the whole window, and properly resize (with it's column) when the window is resized. If I put two controls, they should divide the space by halves, and still should be resized when the window is resized.
Any help, tips?
Upd
Here is an example of the template I'm using.
<DataTemplate x:Key="testCaseDataResultTemplate">
<!-- Test case results -->
<Grid Margin="50,0,0,0" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<!--Test case result property-->
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<!--Is retry / Name-->
<RowDefinition />
<!--Test case number-->
<RowDefinition />
<!--Low limit-->
<RowDefinition />
<!--High limit-->
<RowDefinition />
<!--Measured-->
<RowDefinition />
<!--State-->
<RowDefinition />
<!--Test time-->
<RowDefinition />
<!--Comment-->
</Grid.RowDefinitions>
<!--Is retry / Name-->
<Image Grid.Column="0" Grid.Row="0"
Source="..\Resources\retry16.png"
Stretch="None" HorizontalAlignment="Left"
Visibility="{Binding Path=IsRetry, Converter={StaticResource boolToVisibilityConverter}}" />
<TextBlock Text="fh fhgfhg fhfhfhgfhg fhgfhfhgfhgfhgfhgfhgfhgf hgfhgfhgfhgfhgfhg fhfhgfhgf hgfhgfhfhg fhfhgf rdederserswerv 2" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" TextWrapping="Wrap" MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}"/>
<!--Test case number-->
<TextBlock Text="Number:" Grid.Column="0" Grid.Row="1" />
<TextBlock Text="{Binding Path=TestCaseNumber}" Grid.Column="1" Grid.Row="1" />
<!--Low limit-->
<TextBlock Text="Low limit:" Grid.Column="0" Grid.Row="2" />
<TextBlock Text="{Binding Path=TestCaseData.LimitData.LowLimit}" Grid.Column="1" Grid.Row="2" />
<!--High limit-->
<TextBlock Text="High limit: " Grid.Column="0" Grid.Row="3" />
<TextBlock Text="{Binding Path=TestCaseData.LimitData.HighLimit}" Grid.Column="1" Grid.Row="3" />
<!--Measured-->
<TextBlock Text="Measured" Grid.Column="0" Grid.Row="4" />
<TextBlock Text="{Binding Path=MeasuredValue, Converter={StaticResource valasaConverter}}" Grid.Column="1" Grid.Row="4" />
<!--State-->
<TextBlock Text="Passed: " Grid.Column="0" Grid.Row="5" />
<TextBlock Text="{Binding Path=Passed}" Grid.Column="1" Grid.Row="5" />
<!--Test time-->
<TextBlock Text="Test time: " Grid.Column="0" Grid.Row="6" />
<TextBlock Text="{Binding Path=TestTime, StringFormat={}{0:hh':'mm':'ss'.'ff}}" Grid.Column="1" Grid.Row="6" />
<!--Comment-->
<TextBlock Text="{Binding Path=ShortMessage}"
Grid.Column="0" Grid.Row="7" Grid.ColumnSpan="2"
Visibility="{Binding Path=HasComment, Converter={StaticResource boolToVisibilityColConverter}}"
VerticalAlignment="Stretch"
MaxWidth="400"
TextAlignment="Center">
<TextBlock.ToolTip>
<StackPanel>
<TextBlock Text="{Binding Path=FullMessage}"/>
</StackPanel>
</TextBlock.ToolTip>
</TextBlock>
</Grid>
</DataTemplate>
It's a bit messy, but it is very simple. It has two columns - the captions, and the values. These columns are nothing to do with truncation.
I have tried also this template:
<DataTemplate x:Key="testCaseDataResultTemplate">
<TextBlock Text="Long long text goes here...... ->" HorizontalAlignment="Stretch"/>
</DataTemplate>
The text was of course longer :) It was still truncating, so I blame the listView/GridView, but not the inner template.
I think that this issue maybe is that you need to set the ListView.HorizontalContentAlignment to Stretch. Also the item container style and the item template must have the HorizontalAlignment to Stretch and the Width property must be Auto. Hope this tips helps...
EDIT
Also I think the problem could be the width of the GridViewColumn, that fix the items width
to it's own width. If you are using a single column, maybe you can change the ListView to a ListBox or an ItemsControl, just an idea.
I don't know what your templates looks like but I see a problem like this, it normally lies with a TextBlock that isn't wrapping and/or that the TextBlock's width is longer than it's parent.
Cannot say that I solved the puzzle, but at least it works as I expected. I removed the whole definition with GridView and columns inside, and put ItemTemplateSelector directly in ListView.
So my ListView looks now like this:
<ListView DockPanel.Dock="Top" Name="testCaseResultListView"
ItemsSource="{Binding LogItems}"
ItemContainerStyleSelector="{StaticResource fixSideViewLogItemStyleSelector}"
SelectionMode="Single"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
ItemTemplateSelector="{StaticResource fixSideViewLogItemTemplateSelector}">
That did it! Hope that will help to somebody as well.

Categories

Resources