Hiding flyout of a button - c#

I got my DataTemplate for items and within this DataTemplate I have such code:
<Button x:Name="DoneButton"
Style="{StaticResource ButtonStyle1}"
BorderThickness="1"
Margin="0,0,20,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Grid.Column="2"
Grid.Row="1"
Width="50"
Height="50"
>
<Image Source="Images/WPIcons/checked.png" Width="30" Height="30" Margin="-10,0,-10,0" />
<Button.Flyout>
<Flyout x:Name="myFly">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Uid="myNote" Text="Note: " Style="{StaticResource myText}" />
<TextBox Grid.Row="1" TextWrapping="Wrap" AcceptsReturn="True" Height="40" x:Name="note" Text="{Binding RecentNote, Mode=TwoWay}" Style="{StaticResource TextBoxStyle1}"/>
<Button x:Name="CompletedButton"
Command="{Binding CompletedCommand}"
CommandParameter="{Binding}"
Style="{StaticResource ButtonStyle1}"
BorderThickness="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Grid.Row="2"
Click="CompletedButton_Click"
Content="Done"
MinWidth="80"
Height="40"
/>
</Grid>
</Flyout>
</Button.Flyout>
</Button>
After the flyout for the item has been called and user put his data in it I want to hide this flyout as soon as user hits the "Done" button (x:Name="CompletedButton").
I tried to do that in code behind like:
private void CompletedButton_Click(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
Grid grid = (Grid)VisualTreeHelper.GetParent(button);
Flyout fly = (Flyout)VisualTreeHelper.GetParent(grid);
fly.Hide();
}
But I get cast exception with that I can't cast ContentPresenter to Flyout so I guess it's not the way I look for.
How I can hide this flyout?

I resolved it with creating global DependencyObject on the page. So when you click the button it keeps it and I can call its flyout to hide() from button within this flyout. A bit ugly but works like a charm.

Related

Getting selected item in ListView without selecting an Item on UI

I'm working on a WPF application where I've made a ListView on UI which is two-way binding enabled. This WPF application is being developed for a windows 10 based smartphone. So whenever a user taps an item in the list whose data source is data-binded to back data collection, I've to do some operation for that item in code behind.
Now the problem is, I always receive a null object from the below function whenever the user taps on the item.
CartItem selectedItem = (CartItem)lv_CartItems.SelectedItem;
I only get a filled item object when the user actually selects an item by clicking on ListViewItem rather than tapping on it.
I want to get the selected item when the user taps on it. Is there any workaround available in WPF this problem? I've stuck here
My ListViewItem template looks like this.
<ListView Name="lv_CartItems" Loaded="lv_CartItems_Loaded"
HorizontalAlignment="Center" ScrollViewer.CanContentScroll="False"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Width="250" Height="230" SelectionMode="Single"
>
<ListView.ItemTemplate>
<DataTemplate>
<Viewbox>
<Grid Width="230" Height="110" >
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width=".1*" />
<ColumnDefinition />
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width=".5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border BorderBrush="LightGray" BorderThickness="1"
Grid.Row="0" Grid.Column="0"
Grid.ColumnSpan="6" Grid.RowSpan="3" >
</Border>
<Viewbox Grid.Row="0" >
<Image Name="img_ItemImage"
Source="{Binding Image, Mode=TwoWay }"
Width="20" Height=" 25" />
</Viewbox>
<Viewbox Grid.Column="2" Grid.ColumnSpan="3" VerticalAlignment="Top" >
<TextBlock Name="lbl_ItemName" TextWrapping="Wrap" Width="180" Foreground="Gray"
Text="{Binding Name , Mode=TwoWay }" >
</TextBlock>
</Viewbox>
<Viewbox Grid.Row="1" Margin="10,0" VerticalAlignment="Top" >
<TextBlock Foreground="Gray" >Qty:</TextBlock>
</Viewbox>
<Viewbox Grid.Row="2" Margin="0,0" VerticalAlignment="Top" >
<StackPanel Orientation="Horizontal" >
<Button Name="btn_Minus" FontWeight="ExtraBold" Tag="{Binding SKU_No,Mode=TwoWay}" Padding="0" Width="12"
Resources="{StaticResource cartitembutton}" Click="btn_Minus_Click" >
<Image Source="/Resources\Icons\minus.png" ></Image>
</Button>
<Border BorderThickness="1" Margin="2,0" Width="13" CornerRadius="2" BorderBrush="LightGray" >
<TextBlock Name="lbl_Quantity" FontWeight="Bold" Foreground="Gray"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Quantity , Mode=TwoWay }" >
</TextBlock>
</Border>
<Button Name="btn_Increment" FontWeight="ExtraBold" Width="12"
Resources="{StaticResource cartitembutton}" Tag="{Binding SKU_No,Mode=TwoWay}"
Padding="0"
Click="btn_Increment_Click">
<Image Source="/Resources\Icons\union_10.png" ></Image>
</Button>
</StackPanel>
</Viewbox>
<Viewbox Grid.Row="1" Grid.Column="2" Margin="5,0"
HorizontalAlignment="Left" Grid.ColumnSpan="3" >
<TextBlock Name="lbl_Price" FontWeight="DemiBold"
Text="{Binding Price , Mode=TwoWay}" ></TextBlock>
</Viewbox>
<Viewbox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="3"
VerticalAlignment="Top" Margin="0,0" >
<TextBlock Name="lbl_Appearence"
Text="{Binding Appearance , Mode=TwoWay }"
TextWrapping="Wrap" Foreground="Gray" Width="210" >
</TextBlock>
</Viewbox>
<Viewbox Grid.Column="5" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="2,2"
>
<Button Name="btn_DeleteItem"
Click="btn_DeleteItem_Click"
Resources="{StaticResource cartitembutton}" >
<Image Source="/Resources/Icons/delete.png" ></Image>
</Button>
</Viewbox>
</Grid>
</Viewbox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is how a listVeiw looks like.
You don't actually want the selected item, you want to know which item contained the button that was clicked- whether that item is selected or not.
You can do this with events, but the more "correct" way to do it in WPF is with commands.
Commands are a pattern which separate the logic of an action (e.g. deleting an item) from the visual component that triggers the action (e.g. the button the user clicks). A command includes a parameter, which you can use to specify which item the command is being executed on. There are a couple different types on commands in WPF, but I'll be explaining using RoutedCommand.
In your case you'd first declare your command(s) in your Window:
public static readonly RoutedCommand DeleteItemCommand =
new RoutedCommand("DeleteItem", typeof(MainWindow));
private void OnCanExecuteDeleteItem(object sender , CanExecuteRoutedEventArgs e)
{
e.CanExecute = e.Parameter != null;
}
private void OnExecuteDeleteItem(object sender, ExecutedRoutedEventArgs e)
{
SomeType item = (SomeType)e.Parameter;
//Actually delete the item
}
And you'd add a CommandBinding to your Window which links the command to the methods which handle it:
<Window.CommandBindings>
<CommandBinding Command="local:MainWindow.DeleteItemCommand" CanExecute="OnCanExecuteDeleteItem" Executed="OnExecuteDeleteItem"/>
</Window.CommandBindings>
And finally, to link your delete Button to the command:
<Button Name="btn_DeleteItem" Resources="{StaticResource cartitembutton}" Command="local:MainWindow.DeleteItemCommand" CommandParameter="{Binding}">
<Image Source="/Resources/Icons/delete.png"/>
</Button>
CommandParameter="{Binding}" works because your Button is inside a DataTemplate, so its DataContext will be the item that is being displayed. This lets you check e.Parameter in your routed event methods to see which item is being interacted with.

how to access TextBox inside ListBox itemsSource which is Datatemplate?

I have a ListBox and its ItemsSource is linked with a ComboBox SelectedItem. Its template is associated with a DataTemplate. Everything is fine but how to access each TextBox inside ListBoxItems. I have 5 labels and 2 TextBoxes inside each ListItem. I want to access each and every TextBox and labels inside ListBoxItem. I need some idea how to access each TextBox inside each Item. For example, there is "wbprofileDesc" TextBox in first ListBoxItem. So I need to access this TextBox and write some functionality to it like keypress event. It need to work for each and every TextBox inside all the ListBoxItems individually. Assume there are 5 ListBoxItems. Also I need to fetch other controls also like wbselect(ComboBox), wbdepth, wbwidthvalue and etc. I am using MVVM model for this.
<Window.Resources>
<local:wbItemViewModel x:Key="wbItem"/>
<DataTemplate x:Key="wbObjectsDataTemplate">
<Grid Grid.ColumnSpan="1" Grid.RowSpan="1" Height="Auto" Width="642" Margin="0,0,0,-14">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Width="697" Margin="10,0,0,0" Height="54" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="49*"/>
<ColumnDefinition Width="91*"/>
<ColumnDefinition Width="309*"/>
<ColumnDefinition Width="306*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition/>
<RowDefinition Height="auto" MinHeight="5"/>
</Grid.RowDefinitions>
<Label Content="{Binding WBName_lbl}" Margin="0,3,0,5" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"/>
<ComboBox x:Name="wbselect" Margin="5,0,10,1" Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="0">
<ComboBoxItem x:Name="wbstraight" IsSelected="True" Content="straight"/>
<ComboBoxItem x:Name="wbtapered" Content="tapered"/>
</ComboBox>
<!--KeyDown="{Binding Path=profileDesc}"-->
<!-- KeyDown="profileDesc_KeyDown" -->
<TextBox x:Name="wbprofileDesc" Margin="18,0,20,1" Grid.Column="2" Grid.Row="0" GotFocus="wbprofileDesc_GotFocus"/>
<TextBox x:Name="wbdepth" Text="{Binding ElementName=wbwidthvalue, Path=Content, Mode=OneWay}" Margin="10,0,73,1" Grid.Column="3" Grid.Row="0"/>
<Label x:Name="wbwidthvalue" Margin="10,0,190,5" Grid.Column="2" FontSize="8" Grid.Row="1"/>
<Label x:Name="wbthicknessvalue" Margin="118,0,82,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wblengthvalue" Margin="208,0,0,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wbnexwidthvalue" Margin="10,0,178,5" FontSize="8" Grid.Row="1" Grid.Column="3"/>
<Label x:Name="wbdepthvalue" Grid.Row="1" Grid.Column="3" FontSize="8" Margin="132,0,31,5"/>
<!--<Label x:Name="totalvalue" Margin="30,10,24,16" Grid.Row="3" Grid.Column="3"/>-->
</Grid>
</Grid>
</DataTemplate>
</Window.Resources>
<ListBox x:Name="wbListDataTemplate"
ItemsSource="{Binding wbVisibleItems}"
ItemTemplate="{DynamicResource wbObjectsDataTemplate}"
DataContext="{DynamicResource wbItem}"
Background="{x:Null}"
SelectedItem="{Binding wbSelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsSynchronizedWithCurrentItem="True"
Canvas.Top="51" Height="222" Width="686"/>
Here is an example of you could find the controls in the DataTemplate inside the event handler:
private void wbprofileDesc_GotFocus(object sender, RoutedEventArgs e)
{
TextBox wbprofileDesc = sender as TextBox;
Grid parentGrid = wbprofileDesc.Parent as Grid;
ComboBox wbselect = parentGrid.Children.OfType<ComboBox>().FirstOrDefault(x => x.Name == "wbselect");
Label wbwidthvalue = parentGrid.Children.OfType<Label>().FirstOrDefault(x => x.Name == "wbwidthvalue");
}

How to supress children from invoking parent's event?

I'm creating simple touch-based user comtol web browser. I'm using ManipulationDelta event to pan, zoom-in, zoom-out etc. The browser (Awesomium WebControl) is placed inside a grid of control. When I try to scroll page whole browser moves. How to supress invoking parent's event by childen?
I've set userinput type to ViewInput.Mouse because I want to handle touch by myself.
XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:awe="http://schemas.awesomium.com/winfx" x:Name="_control" x:Class="WebControlTouch.WebBrowser"
mc:Ignorable="d" d:DesignWidth="497" Height="323.333">
<Grid TouchDown="_mainGrid_TouchDown" x:Name="_mainGrid" Background="Honeydew" Grid.Row="0" Margin="0,0,-66,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8*"/>
<ColumnDefinition Width="466*"/>
<ColumnDefinition Width="8*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="84*"/>
<RowDefinition Height="7*"/>
<RowDefinition Height="220*"/>
<RowDefinition Height="12*"/>
</Grid.RowDefinitions>
<awe:WebControl TouchDown="_browser_TouchDown" Visibility="Visible" LoadingFrameFailed="_browser_LoadingFrameFailed" LoadingFrameComplete="_browser_LoadingFrameComplete" LoadingFrame="_browser_LoadingFrame" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="_browser" AddressChanged="_browser_AddressChanged" Width="Auto" Height="Auto" Grid.Row="2" Grid.Column="1" Margin="0,0,1,0"/>
<TextBox Grid.Row="0" HorizontalAlignment="Left" Name="_addressBar" Height="43" Margin="0,10,0,0" TextWrapping="Wrap" Text="Address" VerticalAlignment="Top" Width="146" Grid.ColumnSpan="2"/>
<Button x:Name="_goButton" Grid.Row="0" TouchDown="Button_TouchDown" Content="Go!" HorizontalAlignment="Left" Margin="131,10,0,0" VerticalAlignment="Top" Width="132" RenderTransformOrigin="-0.164,0.514" Height="43" Click="Button_Click" Grid.Column="1"/>
<Button TouchDown="Btn_back" x:Name="_btnBack" Content="Back" Click="Btn_back" HorizontalAlignment="Left" Margin="276,10,0,0" VerticalAlignment="Top" Width="75" Grid.Column="1" Height="20"/>
<Button TouchDown="_btn_forward" x:Name="_btnForward" Content="Forward" HorizontalAlignment="Left" Margin="365,10,0,0" VerticalAlignment="Top" Width="75" Click="_btn_forward" Grid.Column="1" Height="20"/>
<Label x:Name="_Status" Content="Ready" Margin="277,42,130,16" VerticalAlignment="Center" Grid.Column="1" Height="26"/>
<Button x:Name="_exitButton" Content="Exit!" Grid.Column="1" HorizontalAlignment="Left" Margin="365,45,0,0" VerticalAlignment="Top" Width="75" TouchDown="_exitButton_TouchDown"/>
<Button x:Name="_temp" Content="Scroll" Grid.Column="1" HorizontalAlignment="Left" Margin="459.312,10.04,0,0" VerticalAlignment="Top" Width="75" Click="_tempClick"/>
</Grid>
</UserControl>
This means you want some event(s) to stop bubbling (up) the control hierarchy.
All you should usually need to do is marked the event as handled (the event instance you get in your event handler):
e.Handled = true;
In your case should be something like:
private void _browser_TouchDown(object sender, TouchEventArgs e)
{
//...
e.Handled = true;
//...
}

Accessing mediaelement in listbox wp7

I have a MediaElement inside ListBox.How I can get access to "audiop_Copy" by buttons "play/pause"?
<local:TypeTemplateSelector.WithAudio>
<DataTemplate>
<Grid Margin="0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1">
<TextBlock ... />
<StackPanel Height="50" Orientation="Horizontal" Margin="5,0,4,0" MinHeight="50">
</TextBlock>
<Button Click="PlayMedia" Content="Play" />
<Button Click="PauseMedia" Content="Pause" />
</StackPanel>
<MediaElement Name="audiop_Copy" Source="{Binding audioUri}" Stretch="None" HorizontalAlignment="Left" AutoPlay="False"/>
</StackPanel>
</Grid>
</DataTemplate>
</local:TypeTemplateSelector.WithAudio>
2 ways to do it from the spot (possibly there are more). You will need a pointer to your Button that was clicked anyway:
[difficult, inflexible, fragile] In button Click event handler use VisualTreeHelper class to navigate Visual Tree and find the element. Use sender as starting point
[better solution] use Tag property and binding.
<Button Click="PauseMedia" Content="Pause" Tag={Binding ElementName=audiop_Copy} />
And in handler something like that:
private void PauseMedia(object sender, RoutedEventArgs e)
{
var me = ((FrameworkElement) sender).Tag as MediaElement;
}

C# Strange WPF Combobox Behavior

I have simple window.
This is what happens when I click ComboBox:
List appears in upper left corner of screen instead of under Combobox.
XAML:
<Window x:Class="WpfPortOfTestingCamera.VideoSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Video Settings" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" ShowInTaskbar="False" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" SizeToContent="WidthAndHeight" d:DesignHeight="167">
<StackPanel Name="stackPanel1" VerticalAlignment="Top" HorizontalAlignment="Center">
<GroupBox Header="Settings" Name="groupBox1">
<Grid Name="grid1" VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*" />
<ColumnDefinition Width="175*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Resolution:" Height="28" Name="label1" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
<Label Content="Framerate:" Height="28" HorizontalAlignment="Left" Margin="0" Name="label2" VerticalAlignment="Center" Grid.Row="1" />
<ComboBox Grid.Column="1" Height="23" HorizontalAlignment="Left" Margin="0" Name="comboBox1" VerticalAlignment="Center" Width="150" SelectionChanged="comboBox1_SelectionChanged" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="0" Name="comboBox2" VerticalAlignment="Center" Width="150" Grid.Column="1" Grid.Row="1" SelectionChanged="comboBox2_SelectionChanged" />
</Grid>
</GroupBox>
<Label Name="labelSelectedSize" Content="Size # FPS" />
<Button Name="button1" Content="Apply" Click="button1_Click" />
</StackPanel>
</Window>
Instead of opening it directly in the Loaded event, just queue another message on the Dispatcher to open it.
I ran into exactly this and just posted an example at WPF ComboBox DropDown part appears in the wrong place which worked for me. The interested reader can go there to peruse my commentary, but here's the snippet (NOTE: WindoBaseLoadedHandler is the "Loaded=" handler specified in the XAML):
protected void WindowBaseLoadedHandler(object sender, RoutedEventArgs e)
{
...non-essential lines of code removed...
if (DataContext != null)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
this.IsEnabled = false;
LoginDlg loginDlg = new LoginDlg();
loginDlg.ShowDialog();
if (!loginDlg.Success)
{
/*-----------------------------------
* Log on failed -- terminate app...
*----------------------------------*/
...termination logic removed...
}
this.IsEnabled = true;
}));
}

Categories