Avalonia How To Create Custom Popup - avaloniaui

A little explanation first:
This is source code of Popup element
And this is example of using Popup DatePicker and it's xaml
I've tried use this example on empty window like this
Here is result:
So I want to create a OK/Cancel pick panel and use like DateTimePicker Pop and Select what do you want and accept or abort the selections.
How can I create a simple custom picker like this.

Edit: Here is My DateTimePicker and screenshots
After Tap
Ok I analyzed the existing codes for hours. Simply the answer is:
Step 1: Create a presenter class for manage your controls and events for popup. (like DatePickerPresenter
namespace AvaloniaTest.Views {
public class SabriPresenter : PickerPresenterBase
{
...
}
}
Step 2: Create Template for this presenter in your window or resource.
<Window xmlns="bla bla bla"
xmlns:v="using:AvaloniaTest.Views"
Title="AvaloniaTest">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<Window.Styles>
<Style Selector="v|SabriPresenter" >
<Setter Property="Template">
<ControlTemplate>
<Grid Background="AliceBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Panel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock Text="Your content..."/>
</Panel>
<Button Grid.Column="0" Grid.Row="0" Content="OK"/>
<Button Grid.Column="1" Grid.Row="0" Content="Cancel"/>
</Grid>
</ControlTemplate>
</Setter>
</Style>
</Window.Styles>
</Window>
Step 3: Use this presenter wherever you want
<Window xmlns="bla bla"
xmlns:v="using:AvaloniaTest.Views"
>
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button Content="Popeye" Name="sabri"/>
<Popup Name="Popup"
WindowManagerAddShadowHint="False"
StaysOpen="False"
PlacementMode="Bottom"
PlacementTarget="{Binding ElementName=sabri}"
>
<v:SabriPresenter />
</Popup>
</StackPanel>
</Window>
Ta-daa!

Related

Only capture tap event from button contained in ListViewItem without triggering item click - UWP Windows 10

In my UWP app which uses MVVMLight, I have a button contained in my ListViewItem and when clicked I want to display a flyout and provide additional actions for the specific ListViewItem but whenever I tap on the button, I get an error i.e.
System.InvalidCastException: Unable to cast object of
type 'Windows.UI.Xaml.Input.TappedRoutedEventArgs' to
type 'MyApp.ViewModels.ItemViewModel'.
at GalaSoft.MvvmLight.Command.RelayCommand`1.Execute(Object parameter)
at Microsoft.Xaml.Interactions.Core.InvokeCommandAction.Execute(Object
sender, Object parameter) at
Microsoft.Xaml.Interactivity.Interaction.ExecuteActions(Object sender,
ActionCollection actions, Object parameter)
at Microsoft.Xaml.Interactions.Core.EventTr
I understand to some extend why it's happening but how I can I fix this? The button contained in my ListViewItem data template is obviously being passed to the parent which is the listview and the DataTrigger that's defined in the Listview is capturing it.
All I want to do is display a flyout when this button is clicked to provide additional options.
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="{StaticResource SystemControlBackgroundAccentBrush5}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="4"
Width="90"
Height="90"
VerticalAlignment="Center"
Margin="5,5,0,5">
<Image Width="90"
Height="90"
Source="{Binding Logo}" />
</Border>
<Grid Grid.Row="0" Grid.Column="1" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal"
Grid.Row="1" VerticalAlignment="Bottom">
<TextBlock Text="Id:" FontWeight="SemiBold" Foreground="White" VerticalAlignment="Center"/>
<TextBlock Text="{Binding Subject}" Margin="10,0,0,0" Foreground="White" VerticalAlignment="Center"/>
</StackPanel>
<Button Width="30" Height="30"
Command="{Binding AdditionalInfoCommand}"
Grid.RowSpan="4"
Grid.Column="1"
Margin="0,0,12,0">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Stroke="{ThemeResource SystemControlBackgroundAccentBrush}"
Fill="{ThemeResource SystemControlBackgroundAccentBrush}"
StrokeThickness="2">
</Ellipse>
<Image Source="ms-appx:///Assets/Information.png" Width="30" Height="30" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
and my ListView has the following code:
<ListView ItemsSource="{Binding MyList}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
SelectionMode="Single">
<ListView.ItemTemplate>
.... as defined above
</ListView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction Command="{Binding ItemClickCommand}"
CommandParameter="{Binding SelectedItem}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</ListView>
Any ideas on how I can resolve this?
UPDATE 1:
I'll re-phrase my question slightly. I've managed to bind the button displayed on the ListViewItem to a specific click event by introducing a RelayCommand (AdditionalInfoCommand) in the item's ViewModel. So now my main problem is the actual error mentioned above which is triggered after AdditionalInfoCommand and I assume it's because it is being captured by the ItemClickCommand. Strange as you would assume that it is using the same ViewModel.
Is there a way to no trigger the itemclick when this button is tapped?
Thanks.
Thierry
I figured it out.
When I tap the button inside my ListView DataTemplate, the button is being passed the Item's ViewModel which is correct but then the tap event is bubbled up back to the parent which is captured by:
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction Command="{Binding ItemClickCommand}"
CommandParameter="{Binding SelectedItem}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
While there may be a solution to stop the event bubbling, to circumvent the problem, I changed my ItemClickCommand.
It was defined as follows:
private RelayCommand<MyItemViewModel> _itemClickCommand;
public RelayCommand<MyItemViewModel> ItemClickCommand
{
get { return this._itemClickCommand ?? (this._itemClickCommand =
new RelayCommand<MyItemViewModel>((viewModel) =>
ItemClickCommandAction(viewModel))); }
}
I simply changed it to:
private RelayCommand<object> _itemClickCommand;
public RelayCommand<object> ItemClickCommand
{
get { return this._itemClickCommand ?? (this._itemClickCommand =
new RelayCommand<object>((viewModel) =>
ItemClickCommandAction(viewModel))); }
}
I then changed the ItemClickCommandAction to take in an object instead of MyItemViewModel and now, within the method, I check the type of the ViewModel being passed:
private void ItemClickCommandAction(object currentObject)
{
if (currentObject is MyItemViewModel)
{
//go to next page
}
}

WinRT hardcoded ListViewItem vs. DataTemplate, why do they not look/work the same?

I'm new to WinRT so apologies if this is a silly question. I've created the following ListView:
<ListView x:Name="MyListView1"
Grid.Row="1"
Margin="120,300,0,0"
Width="500"
HorizontalAlignment="Left">
<ListViewItem Background="DodgerBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<TextBlock Text="hardcoded value 1" Grid.Column="0"></TextBlock>
<TextBlock Text="hardcoded value 2" Grid.Column="1"></TextBlock>
</Grid>
</ListViewItem>
</ListView>
This looks the way I want it to look, and if you click an item it will select the whole row. However, if I move this into a DataTemplate it doesn't look the same, and you can no longer click the whole row. (If I add an ItemContainerStyle with the target type ListViewItem and set the background to yellow, it will fill it up so it's the same size as the hardcoded ListItem, but you can only click the yellow outline to select it.) This is the code:
<ListView x:Name="MyListView2"
ItemTemplate="{StaticResource MyTemplate}"
ItemsSource="{Binding MyData}"
Grid.Row="1"
Margin="120,0,0,0"
Width="500"
HorizontalAlignment="Left">
</ListView>
And in StandardStyles.xaml:
<DataTemplate x:Key="MyTemplate">
<ListViewItem Background="DodgerBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MyDataOne}" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding MyDataTwo}" Grid.Column="1"></TextBlock>
</Grid>
</ListViewItem>
</DataTemplate>
I don't understand why they don't look/work the same - shouldn't it get populated with the exact same code when you bind it? What do I need to do to make it work?
The problem there is the way you created the datatemplate. Remember that ListViewItem is a wrapper added to any object that needs to be displayed in the list, so when you create a datatemplate that contains a listviewitem you are basically wrapping the object twice. All you need to do is remove the listviewitem element from the datatemplate
<DataTemplate x:Key="MyTemplate">
<Grid Background="DodgerBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MyDataOne}" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding MyDataTwo}" Grid.Column="1"></TextBlock>
</Grid></DataTemplate>

Windows Phone Context Menu Item Text Not Appearing

I have a Windows Phone 8 app using XAML/C#. My app has an ItemsControl that relies on a data template. My DataTemplate looks like the following:
<DataTemplate x:Key="myTemplate">
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding DisplayName}" TextWrapping="NoWrap" Style="{StaticResource PhoneTextLargeStyle}" TextTrimming="WordEllipsis" >
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem x:Name="customerMenuItem" Foreground="White" Header="View Customer Profile" Click="customerMenuItem_Click" Tag="{Binding Path=CustomerName}" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</TextBlock>
<TextBlock Text="{Binding Summary}" TextWrapping="NoWrap" Grid.Row="1" Style="{StaticResource PhoneTextSmallStyle}" />
</Grid>
<StackPanel Orientation="Horizontal" Grid.Column="1"><!-- Stuff here --></StackPanel>
</Grid>
</DataTemplate>
This DataTemplate is referenced in the main part of my XAML as shown here:
<Grid x:Name="ContentPanel" Grid.Row="1" Grid.ColumnSpan="2" Margin="12,0,12,0">
<ScrollViewer>
<ItemsControl x:Name="myItemsControl" ItemTemplate="{StaticResource myTemplate}" ItemsSource="{Binding Customers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
Please note, the "toolkit" namespace comes from clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit. When I hold my finger (or mouse) on the TextBlock, a context menu appears. However, I never see the words "View Customer Profile". I just see a block box that represents the context menu itself. I know that the item is there though. I know because the customerMenuItem_Click event successfully fires. I have a MessageBox in there that shows the value of the Tag. That value is always correct. For some reason though the menu item text is not appearing. What am I doing wrong?
You put Foreground = "White". Context menu is on white background. That is why you don't see your menu item.

Page.Frame.Navigate overlay old page

When I call Page.Frame.Navigate is i possible to navigate to a page smaller than screen size and make it lay over the page i just navigated from in any simple way? The ideal solution would not involve a large framework and the need to rewrite large parts of the application. I am looking for this effect: Windows 8 Music App
I guess I could make a hack by passing a snapshot of the page being navigated from to the new page and using this as a backdrop but I would prefer a cleaner solution. I guess I also could access the navigation stack from the new page and render the old behind.
You could use the Popup element, as William Melani stated. Here's an example:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="1*"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>
</Grid.RowDefinitions>
<Button x:Name="btnPopup" Content="Open Popup" Click="btnPopup_Click_1" Grid.Row="0"></Button>
<Popup IsLightDismissEnabled="True" x:Name="popup1" Grid.Row="1" HorizontalAlignment="Center">
<StackPanel Background="Black">
<Border Background="Blue" BorderThickness="2">
<StackPanel>
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Text="User:" VerticalAlignment="Center" Margin="0,0,10,0" FontSize="20" />
<TextBox Height="40" Width="250" FontSize="20" />
<TextBlock Text="Mail:" VerticalAlignment="Center" Margin="0,0,10,0" FontSize="20" />
<TextBox Height="40" Width="250" FontSize="20" />
</StackPanel>
<Button HorizontalAlignment="Right" Margin="10">Accept</Button>
</StackPanel>
</Border>
</StackPanel>
</Popup>
And the button event:
private void btnPopup_Click_1(object sender, RoutedEventArgs e)
{
popup1.IsOpen = true;
}
Design isn't really my thing.

Silverlight ToolKit DragDrop problem

I have pane with two grid and there is a listbox in both grid. I'd like to add Drag & Drop feature to the pane, so the user can drag a list element in the left listbox and drop it in the right listbox. I found many great tutorials and I could add the appropriate code to my pane but when the application is running and I click on the menu item of my pane it does not load. If I delete the drag & drop code everything works fine, so the problem is definitely the Drag & Drop feature.
<telerikDocking:RadPane x:Class="Module_TestModule1.PaneSzD" telerikDocking:RadDocking.SerializationTag="Module_TestModule1.PaneSzD"
xmlns:telerikDocking="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Docking"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="PaneSzD1" Header="PaneSzD" IsHidden="True">
<StackPanel Orientation="Horizontal">
<Grid x:Name="LeftGrid" Width="250">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<toolkit:ListBoxDragDropTarget AllowDrop="True" Grid.Row="0">
<ListBox Name="lbLRecords">
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox>
</toolkit:ListBoxDragDropTarget>
<StackPanel Grid.Row="1" Height="Auto">
<TextBox Name="tbLRecord" KeyDown="tbLRecord_KeyDown" />
<Button Name="btnLAddRecord" Content="Add Record" Height="30" Click="btnLAddRecord_Click" ></Button>
</StackPanel>
</Grid>
<StackPanel Orientation="Vertical">
<Button Name="btnLMoveRecord" Content="Move Record From Left" Height="30" Click="btnLMoveRecord_Click" Margin="10,5,10,5" />
<Button Name="btnRMoveRecord" Content="Move Record From Right" Height="30" Click="btnRMoveRecord_Click" Margin="10,5,10,5" />
</StackPanel>
<Grid x:Name="RightGrid" Width="250">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<toolkit:ListBoxDragDropTarget AllowDrop="True" Grid.Row="0">
<ListBox Name="lbRRecords">
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox>
</toolkit:ListBoxDragDropTarget>
<StackPanel Grid.Row="1" Height="Auto">
<TextBox Name="tbRRecord" KeyDown="tbRRecord_KeyDown" />
<Button Name="btnRAddRecord" Content="Add Record" Height="30" Click="btnRAddRecord_Click"></Button>
</StackPanel>
</Grid>
</StackPanel>
</telerikDocking:RadPane>
Thanks for any help!
All the info to do this using the Silverlight Control Toolkit can be found here: http://themechanicalbride.blogspot.com/2009/08/new-with-silverlight-toolkit-drag-and.html