I am trying to get Drag and Drop working with WinUI3. In WPF I used to add added both AllowDrop and Drop to a UI element and I was able to receive the filename of a dropped file. However in WinUI3 the method Drop is not beeing executed. What am I doing wrong?
XAML
<Page
x:Class="..."
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="..."
xmlns:helper="..."
xmlns:prop="..."
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<DataTemplate x:Key="Image" x:DataType="helper:ProductImage">
<Border BorderBrush="{x:Bind Path=Color, Mode=OneWay}" BorderThickness="1" Background="Transparent"
AllowDrop="True" Drop="Image_Drop" >
<Grid Width="{Binding ElementName=PIImageSize, Path=Value}"
Height="{Binding ElementName=PIImageSize, Path=Value}" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="2" HorizontalAlignment="Center"
Text="{x:Bind Path=Type, Mode=OneWay}"
Foreground="{x:Bind Path=Color, Mode=OneWay}" />
<Image Grid.Row="1" Stretch="Uniform" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Source="{x:Bind Path=BitmapImage, Mode=OneWay}"/>
<TextBox Grid.Row="2" Text="{x:Bind Path=Path, Mode=TwoWay}" />
</Grid>
<Border.ContextFlyout>
</Border.ContextFlyout>
</Border>
</DataTemplate>
</Page.Resources>
...
</Page>
Code
private void Image_Drop(object sender, DragEventArgs e)
{
// Function is not executed
}
You also have to add the DragOver event, to accept the operation:
private void Image_DragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy;
}
I have declared some Datatemplates for my Collectionviews Header to use as an Template.
<ResourceDictionary>
<!--#region HeaderTemplates-->
<DataTemplate x:Key="translationHeaderTemplate">
<Frame x:Name="translationDropTarget" Margin="5">
<Label Style="{x:StaticResource boldLabelStyle}" Text="{Binding SolutionDisplay}" FontSize="Medium" HorizontalOptions="Center" HeightRequest="50" VerticalOptions="Center" x:Name="FrameLabel"></Label>
<Frame.GestureRecognizers>
<DropGestureRecognizer AllowDrop="True" DropCommand="{Binding DropOverCommand}">
</DropGestureRecognizer>
</Frame.GestureRecognizers>
</Frame>
</DataTemplate>
<DataTemplate x:Key="pictureHeaderTemplate">
<Frame x:Name="pictureDropTarget" Margin="5">
<Image Source="{Binding SolutionIconString}" HorizontalOptions="FillAndExpand" MinimumWidthRequest="50" HeightRequest="100" VerticalOptions="CenterAndExpand" x:Name="FrameImage"></Image>
<Frame.GestureRecognizers>
<DropGestureRecognizer AllowDrop="True" DropCommand="{Binding DropOverCommand}">
</DropGestureRecognizer>
</Frame.GestureRecognizers>
</Frame>
</DataTemplate>
<DataTemplate x:Key="ttsHeaderTemplate">
<Frame x:Name="ttsDropTarget" Margin="5">
<forms:AnimationView x:Name="XAnim" AutoPlay="true" VerticalOptions="CenterAndExpand" RepeatMode="Infinite" HorizontalOptions="CenterAndExpand" Animation="soundIcon.json"
Clicked="XAnim_Clicked" ></forms:AnimationView>
<Frame.GestureRecognizers>
<DropGestureRecognizer AllowDrop="True" DropCommand="{Binding DropOverCommand}">
</DropGestureRecognizer>
</Frame.GestureRecognizers>
</Frame>
</DataTemplate>
<!--#endregion-->
<DataTemplate x:Key="translationTemplate">
<Frame HasShadow="True" CornerRadius="15" VerticalOptions="Start" HeightRequest="70">
<StackLayout>
<Label
Text="{Binding DisplayString}"
Style="{x:StaticResource mediumlabelStyle}"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
FontSize="Small">
</Label>
</StackLayout>
<Frame.GestureRecognizers>
<DragGestureRecognizer
DragStartingCommand="{Binding Path=BindingContext.DragStartingCommand, Source={x:Reference ViewCollection}}"
DragStartingCommandParameter="{Binding .}"/>
</Frame.GestureRecognizers>
</Frame>
</DataTemplate>
<vokabelmodul:VocabularyViewTemplateSelector
x:Key="vocViewTemplateSelector"
TranslationTemplate="{StaticResource translationHeaderTemplate}"
PictureTemplate="{StaticResource pictureHeaderTemplate}"
TTSTemplate="{StaticResource ttsHeaderTemplate}"/>
</ResourceDictionary>
</ContentPage.Resources>
And I'm trying to consume it within my CollectionView with the templateselector :
<ContentPage.Content>
<AbsoluteLayout>
<StackLayout
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<Frame>
<StackLayout>
<Label Style="{x:StaticResource labelStyle}" FontSize="Small" x:Name="TimerLabel" Text="{Binding Remaining}"></Label>
<ProgressBar x:Name="Progress" Progress="{Binding Progress}" ProgressColor="Blue"></ProgressBar>
</StackLayout>
</Frame>
<StackLayout x:Name="InnerStack">
<CollectionView
x:Name="ViewCollection"
ItemsSource="{Binding ViewObjects}"
VerticalOptions="Center"
Margin="5"
ItemTemplate="{StaticResource translationTemplate}"
HeaderTemplate="{StaticResource vocViewTemplateSelector}"
Header="{Binding .}"
>
<CollectionView.EmptyView>
<Label Text="No VocabularyItems!" Style="{x:StaticResource boldLabelStyle}"></Label>
</CollectionView.EmptyView>
<CollectionView.ItemsLayout>
<GridItemsLayout
Orientation="Vertical"
HorizontalItemSpacing="5"
VerticalItemSpacing="5"
Span="2"/>
</CollectionView.ItemsLayout>
</CollectionView>
</StackLayout>
</StackLayout>
</AbsoluteLayout>
</ContentPage.Content>
But when I run the Programm I'm always getting "System.InvalidOperationException: 'LoadTemplate should not be null'".
When I'm binding my HeaderTemplate directly like this:
HeaderTemplate="{StaticResource someHeaderTemplate}"
it works just fine.
I've added a log and breakpoint to my TemplateSelector Class but OnSelectTemplate doesn't even get called.
I've also used another Templateselector for my ItemTemplate and that one worked just fine.
Any Help would be appreciated.
In your xaml page, your DataTemplate tag does not add any data or styles, you need to add styles to each DataTemplate tag.
You have not bound the Header data of the CollectionView. You need to add Header="{Binding ViewObjects}" to your CollectionView tag.
This is my xaml code for your reference, I hope it can solve your problem:
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="someHeaderTemplate">
<Label Text="aaa" BackgroundColor="LightPink"></Label>
</DataTemplate>
<DataTemplate x:Key="someOtherHeaderTemplate">
<Label Text="bbb" BackgroundColor="Green"></Label>
</DataTemplate>
<DataTemplate x:Key="someThirdHeaderTemplate">
<Label Text="ccc" BackgroundColor="Yellow"></Label>
</DataTemplate>
<nameSpace:templateSelector x:Key="templateSelector"
first="{StaticResource someHeaderTemplate}"
second="{StaticResource someOtherHeaderTemplate}"
third="{StaticResource someThirdHeaderTemplate}"/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<CollectionView
x:Name="ViewCollection"
Header="{Binding ViewObjects}"
ItemsSource="{Binding ViewObjects}"
VerticalOptions="Center"
Margin="5"
HeaderTemplate="{StaticResource templateSelector}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label></Label>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
I'm trying to implement a Flyout menu in a Windows 10 App (using MVVM) that opens when holding down an item of a GridView. I've been looking and I haven't been able to find any examples that works for me. The Flyout menu is not opening to display options. Does anyone know how can I do it?
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<FlyoutBase.AttachedFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Command="{Binding DeleteCommand}"/>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<Image Source="{Binding Dictionary}" Height="25"/>
<TextBlock Text="{Binding Title}" Foreground="White" Width="170"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
Note: Solution found in https://marcominerva.wordpress.com/2013/12/17/using-a-behavior-to-open-attached-flyouts-in-winows-81-store-apps/
I think what you want to set is StackPanel.Flyout instead of FlyoutBase
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.Flyout>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Command="{Binding DeleteCommand}"/>
</MenuFlyout>
</StackPanel.Flyout>
<Image Source="{Binding Dictionary}" Height="25"/>
<TextBlock Text="{Binding Title}" Foreground="White" Width="170"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
Alternatively if this doesn't work for you you can target the GridViewItem.Flyout
<GridView>
<GridView.Resources>
<Style TargetType="GridViewItem">
<Setter Property="Flyout">
<Setter.Value>
<MenuFlyout>
<MenuFlyoutItem Text="Delete" Command="{Binding DeleteCommand}"/>
</MenuFlyout>
</Setter.Value>
</Setter>
</Style>
</Gridview.Resources>
I've been trying to use Attached Behaviors in a simple Windows Store App using the MVVM Light framework. Since we can't use System.Windows.Interactivity, as in Windows Phone, I've been using both Windows.UI.Interactivity and WinRtBehaviors lybraries. They work well but the problem is that I can't declare an attached behavior inside a data template.
What I really want is to attach a command to any item in a GridView, so that I can pass the item id as the parameter. Since that attached behavior doesen't work, the only solution I found consists on using the "SelectionChanged" event of the GridView and pass the SelectedItem as the parameter to a property in the ViewModel:
<GridView Grid.Row="1"
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemsGridView"
AutomationProperties.Name="Items"
TabIndex="1"
Padding="116,136,116,46"
ItemsSource="{Binding GeoTopArtists.topartists.artist}"
SelectionMode="Single"
SelectedItem="{Binding SelectedArtist, Mode=TwoWay}"
IsSwipeEnabled="False"
IsItemClickEnabled="False">
<WinRtBehaviors:Interaction.Behaviors>
<Win8nl_Behavior:EventToCommandBehavior Event="SelectionChanged" Command="SelectArtistCommand" CommandParameter="{Binding SelectedArtist.mbid}"/>
</WinRtBehaviors:Interaction.Behaviors>
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding image[4].text}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding name}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding url}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
It would be very nice doing something like that (where there's no need to have a SelectedArtist property in the ViewModel)
<GridView Grid.Row="1"
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemsGridView"
AutomationProperties.Name="Items"
TabIndex="1"
Padding="116,136,116,46"
ItemsSource="{Binding GeoTopArtists.topartists.artist}"
SelectionMode="None"
IsSwipeEnabled="False"
IsItemClickEnabled="False">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding image[4].text}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding name}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding url}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
<WinRtBehaviors:Interaction.Behaviors>
<Win8nl_Behavior:EventToCommandBehavior Event="Tapped" Command="SelectArtistCommand" CommandParameter="{Binding Artist.mbid}"/>
</WinRtBehaviors:Interaction.Behaviors>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
This link may help you out. The dependency property is defined and hooked to a command in view model. So whenever there is interaction in view, the selected item can be sent as commanding parameter which is clearly demonstrated in this video.
i've a contentcontrol in my Wpf-App (MVVM) which is bound to an object and displays the objects properties in textboxes, so the user can edit the values of the properties.
i have to buttons in my control "Ok" and "Cancel".. I would like to use UpdateSourceTrigger="Explicit" so that the ViewModel only gets updated when the user explicitly clicks 'Ok', rather than updating as textbox values are modified. How do i achive this.
this is how my viewmodel looks like..
class NeedViewModel : CarePlanEntityViewModelBase
{
public CPLNursingNeedVersion CurrentNeedVersion
{
get { return currentNeedVersion; }
set
{
currentNeedVersion = value;
this.OnPropertyChanged("CurrentNeedVersion");
}
}
}
this is how my view looks like
<DataTemplate x:Key="NeedDataEntryDataTemplate">
<Border Background="White"
BorderThickness="2"
BorderBrush="#4682B4"
local:PublishReadOnlyProperty.Observe="True"
local:PublishReadOnlyProperty.ActualWidth="{Binding Path=Width,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}"
MinWidth="410">
<Grid Name="mainGrid">
<Grid.BindingGroup>
<BindingGroup>
</BindingGroup>
</Grid.BindingGroup>
<Grid.RowDefinitions>
<RowDefinition Height="28" MinHeight="28"/>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7" MaxWidth="7"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="68" MaxWidth="75"></ColumnDefinition>
<ColumnDefinition Width="10" MaxWidth="10"></ColumnDefinition>
<ColumnDefinition Width="68" MaxWidth="75"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Padding="0,3,0,3"
Name="label9"
Grid.Row="1" Grid.Column="1"
Margin="3"
FontSize="13"
HorizontalAlignment="Left" >Voimassaoloaika:</Label>
<hcw:HCWDateTimePicker Padding="0,3,0,3"
x:Name="startDateTimePicker"
Grid.Row="1" Grid.Column="2"
Margin="5,3,3,3"
FontSize="13"
HorizontalAlignment="Left"
MaxWidth="120"
DateControlMode="Mandatory"
SelectedDate="{Binding Path=CurrentNeedVersion.ValidFromDate,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
DisplayMode="DateOnly" />
<Label Padding="0,3,0,3"
Name="label8"
Grid.Row="1" Grid.Column="3"
Margin="3,3,3,3"
HorizontalAlignment="Center"
FontSize="13">-</Label>
<hcw:HCWDateTimePicker x:Name="endDateTimePicker"
Padding="0,3,0,3"
Grid.ColumnSpan="5" Grid.Row="1" Grid.Column="4"
Margin="3"
FontSize="13"
HorizontalAlignment="Left"
MaxWidth="120"
DisplayMode="DateOnly"
SelectedDate="{Binding Path=CurrentNeedVersion.ValidToDate,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Label Name="label26"
Padding="0,3,0,3"
FontSize="13"
Grid.Row="2" Grid.Column="2"
Margin ="20,3,3,3"
HorizontalAlignment="Left"
Grid.ColumnSpan="6">Huomiomerkitty</Label>
<CheckBox Padding="0,3,0,10"
Grid.Row="2" Grid.Column="2"
IsChecked="{Binding Path=CurrentNeedVersion.IsNoteworthy,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Name="note"
FontSize="13"
Margin="3,3,20,3"
VerticalAlignment="Center"
HorizontalAlignment="Left"
IsEnabled="True" />
<ContentControl Content="{Binding}"
Grid.Row="3" Grid.ColumnSpan="9"
ContentTemplate="{DynamicResource ClassificationSelectorDataTemplate}"/>
<Label Padding="0,3,0,3"
Grid.Row="4" Grid.Column="1"
Margin="3"
FontSize="13"
Name="needLabel"
HorizontalAlignment="Left" >Tarve:</Label>
<hcw:HCWTextBox Padding="3,3,0,3"
Grid.Row="4" Grid.Column="2" Grid.ColumnSpan="6"
FontSize="13"
Margin="3"
Name="needTextBox"
Text="{Binding Path=CurrentNeedVersion.NeedText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap"
AcceptsReturn="True" />
<Label Padding="0,3,0,3"
Margin="3"
Name="goalLabel"
FontSize="13"
Grid.Row="8" Grid.Column="1" Grid.ColumnSpan="1">Tavoite:</Label>
<TextBox Padding="0,3,0,3"
Grid.Row="8" GridColumn="2" Grid.ColumnSpan="6"
FontSize="13"
Margin="3"
Text="{Binding Path=CurrentNeedVersion.GoalText, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch"
Name="goalTextBox"
TextWrapping="Wrap"
AcceptsReturn="True" />
<Label Name="temporaryLabel"
Padding="0,3,0,3"
FontSize="13"
Grid.Row="9" Grid.Column="2" Grid.ColumnSpan="6"
Margin="20,3,3,3"
HorizontalAlignment="Left">Keskeneräinen</Label>
<CheckBox Padding="0,3,0,10"
Grid.Row="9" Grid.Column="2"
Name="temporaryCheckBox"
FontSize="13"
Margin="3,3,20,3"
VerticalAlignment="Center"
HorizontalAlignment="Left"
IsEnabled="True" />
<Button Name="acceptButton"
Command="{Binding Path=AcceptNeedDEC}"
Margin="0,0,0,7"
Grid.Row="10" Grid.Column="5"
FontSize="13"
MinWidth="68"
Content="OK"
VerticalAlignment="Center"
Background="WhiteSmoke" />
<Button Command="{Binding Path=CloseDEC}"
Name="cancelButton"
Margin="0,0,0,7"
Grid.Row="10" Grid.Column="7"
HorizontalAlignment="Right"
FontSize="13"
MinWidth="68"
Content="Peruuta"
VerticalAlignment="Center"
Background="WhiteSmoke" />
</Grid>
</Border>
</DataTemplate>
You need to do it in code-behind:
var bindingExpression = BindingOperations.GetBindingExpression(startDateTimePicker, HCWDateTimePicker.SelectedDateProperty);
bindingExpression.UpdateSource();
You could take all of the properties the View is binding to and place them in a different class. Then have two instances of that class in the ViewModel, one public for data binding, and a private one. Once the button is clicked, copy the values from the public one to the private one, then run all of your logic against the private one.