classic binding works but compiletime binding acts only onetime - xaml

I have a mistake in my code, but I cannot see it. So I have a FlipView which has multiple DataTemplates. Now I want the view to be updated on a PropertyChange in the vm - so I use databinding.
But if I use compile time Binding, the binding only behave as it would be set to OneTime - even if the mode is set to OneWay or TwoWay. So I thought they may be something wrong with the OnPropertyChanged event- but I could not find anything. Therefore I tried to switch to classic binding - and it works. So my question is what I am doing wrong with x:Bind?
Here a simplified version of the XAML:
<Page
[...]
DataContext="{Binding Source={StaticResource Locator}, Path=GalleryViewModelInstance}">
<Page.Resources>
[...]
<DataTemplate x:Name="FlipImageTemplate" x:DataType="gallery:IMediaAttachmentViewModel">
<Image Stretch="UniformToFill"HorizontalAlignment="Center" >
<Image.Source>
<BitmapImage UriSource="{Binding AttachmentViewModel.RelativeAttachmentPath, Mode=OneWay, Converter={StaticResource UriConverter}}" />
</Image.Source>
</Image>
</DataTemplate>
<DataTemplate x:Name="FlipVideoAudioTemplate" x:DataType="gallery:IMediaAttachmentViewModel">
[...]
</DataTemplate>
<DataTemplate x:Name="FlipPDFTemplate" x:DataType="gallery:IMediaAttachmentViewModel" >
[...]
</DataTemplate>
<DataTemplate x:Name="FlipOtherTemplate" >
[...]
</DataTemplate>
<local:BigPictureDataTemplateSelector x:Key="BigPictureDataTemplateSelector"
ImageTemplate="{StaticResource FlipImageTemplate}"
VideoAndAudioTemplate="{StaticResource FlipVideoAudioTemplate}"
PdfTemplate="{StaticResource FlipPDFTemplate}"
OtherTemplate="{StaticResource FlipOtherTemplate}"/>
</Page.Resources>
<RelativePanel x:Name="relativePanel" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Padding="40,40,40,40">
<FlipView x:Name="FlipView"
SelectedIndex="{x:Bind ViewModel.FilpViewIndex, Mode=TwoWay}"
ItemsSource="{x:Bind ViewModel.GalleryDataViewModels, Mode=TwoWay}"
ItemTemplateSelector="{StaticResource BigPictureDataTemplateSelector}">
</FlipView>
[...]
</RelativePanel>
</Page>
So if I change the binding to x:bind it is not updating the view (as the Mode would be set to OneTime)
<BitmapImage UriSource="{x:Bind AttachmentViewModel.RelativeAttachmentPath, Mode=OneWay, Converter={StaticResource UriConverter}}" />

Related

Xaml Internal Error error WMC9999: Object reference not set to an instance of an object

This has come up a few times, and I've been struggling with it all day in a UWP app.
My specific issue was that I was using x:Bind inside a ContentTemplate that was inside a DataTemplate:
<DataTemplate x:DataType="IFactionMember">
<Button Command="{x:Bind **Property of IFactionMember**}"> // Good
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Padding="10,0">
<TextBlock Text="{x:Bind **Property of IFactionMember**}" /> // Bad
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
You cannot do this :(
You could use {Binding} instead for your scenario, for example:
<ListView x:Name="listview" ItemsSource="{x:Bind members}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:IFactionMember">
<Button >
<Button.Template>
<ControlTemplate TargetType="Button" >
<Grid Padding="10,0">
<TextBlock Text="{Binding testtext}" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
x:bind lacks some of the features of {Binding}, in x:Bind, Path is rooted at the Page by default, not the DataContext, it seems like if you are using x:bind here, it will try to find the property at the MainPage, so that it will not find the correct property.

Change listview selecteditem datatemplate UWP

I'm trying to change the datatemplate of a selected item in a listview, everything I have found is overly complicated or obsolete.
I've tried using behaviours but it still doesn't work. this is what I am after
<UserControl.Rescources>
<DataTemplate x:DataType="dt" x:Key="notselected">
<Grid>
<Textblock Text="{Binding Title}" Foreground="White"/>
<Image Source="ms-appx:///Assets/myimage.png"/>
</Grid>
</DataTemplate>
<DataTemplate x:DataType="dt" x:Key="selected">
<Grid>
<Textblock Text="{Binding Title}" Foreground="Black"/>
<Image Source="ms-appx:///Assets/myselectedimage.png"/>
</Grid>
</DataTemplate>
</UserControl.Rescources>
<ListView x:Name="listview" ItemTemplate="{StaticResource TMP1}">
<ListView.ItemContainerStyle>
<StaticResource ResourceKey="ListViewItemStyle1"/>
</ListView.ItemContainerStyle>
and just to have it switch to TMP2 while selected
is this possible?
thanks
In your ListView you need to set ItemTemplateSelector to your implementation of DataTemplateSelector. In the code above, you have set ItemTemplate
Assuming TMP1 refers to your DataTemplateSelctor it would look like <ListView x:Name="listview" ItemTemplateSelector="{StaticResource TMP1}"...

Data Binding in splitview error

I'm trying to use a SplitView whose Buttons come from data binding. Here is the code:
<SplitView Name="AnnouncementSplitView"
DisplayMode="CompactInline"
OpenPaneLength="200"
CompactPaneLength="56"
HorizontalAlignment="Left" Grid.Row="1">
<ListView ItemsSource="{x:Bind Parts}"
SelectionMode="Single"
Name="CongregationList"
SelectionChanged="LoadAnnouncements">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:Part">
<StackPanel Orientation="Horizontal">
<TextBlock Name="PartImage"
Text=""
FontFamily="Segoe MDL2 Assets"/>
<TextBlock Name="PartName"
Text="{x:Bind PartName}"
Margin="20,0,0,0"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</SplitView>
I get an error at the following line:
x:DataType="data:Part"
that the class Part does not exist in the namespace defind by data although it does..
The mistake was that that I had created the class after I wrote the code in XAML. So when it was written the compiler tried to find a nonexisting class. All I had to do is rewrite the XAML code, clean and rebuild the solution...

Using different databinding sources within ListBox and ContextMenus

Here is the XAML:
<ListBox ItemsSource="{Binding Documents}" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" FontSize="12" FontWeight="Bold" />
<TextBlock Text="{Binding ID}" FontSize="10" FontStyle="Italic" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding AddDocumentToCategoryContextMenuCommand}" Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Ok so the ListBox's ItemSource is bound to the Documents collection in the VM and properly renders the Titles and IDs
The Context Menu's ItemSource is bound to the CategoryList collection in the VM and properly renders the list of categories.
The problem I have is with the Command Binding:
Command="{Binding AddDocumentToCategoryContextMenuCommand}"
Since the ItemSource for the ContextMenu is already set, it tries to get the AddDocumentToCategoryContextMenuCommand from CategoryList. Obviously the command is not there, it is a member of the VM.
I do not want any references to the VMs or Models in the XAML. Everything is constructed using Unity and VM-View is associated in App.xaml:
<Application.Resources>
<DataTemplate DataType="{x:Type vms:FeedViewModel}">
<views:FeedView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:DocumentsViewModel}">
<views:DocumentsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vms:ManagementViewModel}">
<views:ManagementView/>
</DataTemplate>
<DataTemplate DataType="{x:Type dev:DevelopmentViewModel}">
<dev:DevelopmentView />
</DataTemplate>
</Application.Resources>
How can I databind to a member of the VM from within the ContextItem.
Thanks.
UPDATED edit #1 starts Here
Here is the updated xaml (but still not working but some insight gained):
<ListBox ItemsSource="{Binding Documents}" x:Name="Results" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}" FontSize="12" FontWeight="Bold" />
<TextBlock Text="{Binding ID}" FontSize="10" FontStyle="Italic" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding ElementName=Results, Path=DataContext.AddDocumentToCategoryContextMenuCommand}" Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
I have this example working for a simple example that does not use a ContextMenu. It appears that the ContextMenu (even though attached to the ListBox) is not part of the user control visual tree. The binding always comes back null / not found. I think the ContextMenu, because it is a floating "window" is constructed in its own tree and therefore cannot find the ListBox call "Results" in order to access the ListBox's DataContext.
Any thoughts on this? Any recommendations on how deal with?
Edit #2 Starts Here
In case you are are wondering, figured out the answer to the binding question:
This binding works:
Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AddDocumentToCategoryContextMenuCommand}
Hope this helps others with the same question.
One last update for completeness.
In order for the command to know which context menu item was clicked on, I had to change the xaml slightly (silly oversight):
<ListBox.ContextMenu>
<ContextMenu x:Name="Context" ItemsSource="{Binding CategoryList}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.AddDocumentToCategoryContextMenuCommand}"
CommandParameter="{Binding Category.ID}"
Header="{Binding Category.Name}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ListBox.ContextMenu>
Again, hope this helps others.
Use the ElementName property of the binding to specify that. You'd end up with something like this:
Command="{Binding ElementName=ViewModelObject
Path=AddDocumentToCategoryContextMenuCommand}"

How to get control parent DataContext for element to element databinding?

Suppose I have a user control which datacontext is bound to a VM. This VM has a property for a list MyList.
Inside this user control I have a ComboBox, I want to set following kind of xaml
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel HorizontalAlignment="Stretch">
<sdk:DataGrid ItemsSource="{Binding YourList}" IsReadOnly="True" AutoGenerateColumns="False" >
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<!-- ...... -->
<sdk:DataGridTemplateColumn Header="User" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ElementName=LayoutRoot, Path=DataContext.MyList}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding UserID}" ></ComboBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
</Grid>
but it is not working.
How to resolve this problem?
This worked form me. This was the ItemSource for a ComboBox that was within a DataGrid:
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=sdk:DataGrid},
Path=DataContext.Teams}">
Are you trying to get to the main VM from within the UserControl? take a look at this solution. http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx