I want to show a popup in a page on a event. I have added a popup in a page's definition. It works fine for the 1st time. But since Popup is not a part of visual-tree, the popup gets created again when visiting the page next time. how can I avoid this? the only option I know is to write a static popup in code-behind. But is there any way I can do this in xaml? (or may be in VM)
this is my code in XAML.
<Popup Grid.Row="2" x:Name="popup" IsOpen="{Binding VenueListOpen}">
<ScrollViewer Height="600" Margin="0,0,0,20" Background="#55000000">
<StackPanel Width="{Binding DeviceWidth}">
<ItemsControl ItemsSource="{Binding EventsList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Margin="20,0" Background="{Binding BindsDirectlyToSource=True, Converter={StaticResource EventRowBackgroundConverter}}">
<TextBlock Margin="20,5" FontSize="30" Text="Metlife stadium" TextWrapping="Wrap"/>
<TextBlock Margin="20,5" Foreground="SkyBlue" Text="www.metlifestadium.com" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</Popup>
How about setting its Visible property to false or true when you enter the page?
I have found a solution to this. May be there are better solution but this works for me:
in code behind, detach the binding by setting it to null. So whenever you move away the current popup will become orphan, and when u visit the page again, navigation will create new page as well as new popup up. but this time only new popup will appear, because the older popup is not in bound with datacontext so binding for IsOpen will not affect any older instance of that popup.
Related
Im new in wpf programming and i have an application with MVVM. I have a StackPanel and inside the StackPanel there is a ItemsControl named ListView and the Itemsource is my ObserveCollection NewProducts which conatins ProductID and Name.
So what is my code does, well it generates buttons with Names from my Collection NewProducts and i wanna give this buttons Command that triggers when i click on them.
I try this:
<StackPanel Grid.Row="1">
<ItemsControl x:Name="ListViewProducts" ItemsSource="{Binding NewProducts}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="10" Width="auto" Height="auto">
<StackPanel>
<Border Width="100" Height="40" CornerRadius="5">
<Button Content="{Binding Name}" Tag="{Binding ProductId}" FontWeight="Bold" Command="{BindingSaleViewModel.SendCommand}"/>
</Border>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
But when i run my program and when i click on my buttons nothing happens. Its because the Command that i have in my SaleViewModel was not found in Product which is my Model class. And i wanna know if i can somehow get the path to my Command in my ViewModel.
Thanks, and please forgive me mine English, I know its bad.
Binding methods in WPF is unfortunately not that simple.
The command is actually a class, that implements the ICommand interface.
You can find an example here: How to Bind a Command in WPF.
Otherwise you can bind the click event to a method in code-behind <Button Click="Button_Click"/>
In code-behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
// Add your code here...
}
Give your root element a name. eg:
<UserControl x:Class="blah"
other stuff
x:Name="root">
Then you can reference the root element in your binding, who's datacontext will (presumably?) be your SaleViewModel:
<Button Content="{Binding Name}" Tag="{Binding ProductId}" FontWeight="Bold"
Command="{Binding DataContext.SendCommand, ElementName=root}"
CommandParameter="{Binding}"/>
Also note the CommandParameter binding which will pass the button's data context (Product) through to your command, otherwise you won't know which product the command relates to.
I wrote an example application that highlights the issue, which might have to do with focus-scope because it's whenever a ToolBar is involved and a UserControl is unloaded when switching tabs.
The main window contains a Menu with a File->New command and a TabControl that displays a collection of "Box" instances:
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Command="New"/>
</MenuItem>
</Menu>
<TabControl ItemsSource="{Binding Boxes}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Width="40"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<local:BoxView/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</DockPanel>
Each "Box" instance has a Name property displayed in the tab header, and the rest of it is displayed in a "BoxView" UserControl. The "BoxView" has a ToolBar, the first button of which becomes the focus hog in the mentioned use case. The "BoxView" also displays a collection of "Compartments" that are inside each "Box" instance:
<StackPanel>
<ToolBarTray IsLocked="True">
<ToolBar>
<Button Content="Focus hog"/>
</ToolBar>
</ToolBarTray>
<ItemsControl ItemsSource="{Binding Compartments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CompartmentView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Each "Compartment" instance has a TotalValue property simply displayed in a TextBox in a "CompartmentView" UserControl:
<StackPanel>
<TextBox Text="{Binding TotalValue}"/>
</StackPanel>
And the problem is...
If I click on the TextBox of any one of the CompartmentView's, and then click a different tab of the main window, the first button of the ToolBar of the BoxView is focused (the focus hog one), disabling commands working in the main window.
It can be observed commands are disabled when opening the File menu. But after closing the menu and reopening, commands are enabled again.
How do I prevent the ToolBar in the nested UserControl from being focused when switching tabs?
Or perhaps I'm going at this wrong... how do I prevent focus from being set when switching tabs?
Update
The following link is a video on youtube where I explain the problem with the application.
https://youtu.be/0T5LK3CYxgw
Solution update
Thanks to themightylc for the answer, the issue was clearly a keyboard focus problem when the focused visual control (any selected "CompartmentView" or "BoxView" control) was unloaded while changing the selected tab in the TabControl. The solution was to focus on the TabControl itself in the main window whenever the tab selection changed:
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
(sender as TabControl).Focus();
}
Thanks also to Christoph Nahr's response for the solution on this msdn thread: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f5de6ffc-fa03-4f08-87e9-77bbad752033/a-focusscope-nightmare-bug-commands-are-disabled?forum=wpf
<Button Content="Focus hog" Focusable="False" />
This solves the problem you're having. Focusable is a DependencyProperty If you still want to access the ToolBar via Keyboard-Focus, you can bind it or set it from code-behind when the Tab-Switch is complete.
You can of course set it via Style so you don't have to set it on every element of the ToolBar.
I have a Page and a viewmodel is set as its datacontext. in that page I have a list. which is populating through a property in the viewmodel. List has a user control. and that user control has a button. I want that button to be bind with a command that is in viewmodel. Is there anyway to do that?
<Page DataContext=PageViewModel>
...
<ScrollViewer Grid.Row="3" Margin="20,0" Visibility="{Binding ByVenueSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel>
<ItemsControl ItemsSource="{Binding EventsListByVenue}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<myControls:EventDetails /> <!--in this control i want to bind a command available in PageViewModel-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
...
</Page>
with help of #FunksMaName, I solved this. I am sure there are more elegant and better approach, but yet this is a quick & easy solution for me:
<Button Style="{StaticResource NoHighlightButtonStyle}" Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}" Visibility="{Binding link,Converter={StaticResource DataAvailabilityToVisibilityConverter}}" Command="{Binding Path=Event.LinkCommand,Source={StaticResource Locator}}" >
<TextBlock Margin="0,5" Foreground="SkyBlue" Text="{Binding link}" TextWrapping="Wrap" FontSize="16"/>
</Button>
things to note:
i think xaml searched the command parameter in context of command only, so it was giving me null parameter, while the same binding was working fine for textblock inside Button. So i tricked it to store the value in tag, and used it from there.
Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}"
I put one button in listpicker full mode template. I want when this button is pressed. It Just invoke my defined event. Not act as normal tap on listpicker And closes the full mode of listpicker.
Please see screenshot below.
To include the button in the listPicker full mode, you have to define the data template as such. Go through the listPicker given here
<DataTemplate x:Name="PickerFullModeItemTemplate">
<StackPanel Orientation="Horizontal" Margin="16 21 0 20">
<Button Click="event">
<Button.Content>
<StackPanel>
<Image Source="myImg.png"/>
<TextBlock Text="test"/>
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
</DataTemplate>
For the behavior you require. Try and test by handling event function on click event in the button. I guess it should work. If not then you have to use popUp instead of listPicker. Or you would have to define your own UserControl in the worst case.
I am trying to create a menu bar for my application. I have created a collection in xaml that I will contain menu items that my menu will bind to.
In xaml I have created an array that I use as my static resource for binding.
<coll:ArrayList x:Key="MenuOptionsList">
<model:DashboardMenuBarItem
Icon="the location of an image in my images folder"
DisplayName="The test that will appear under my button"
CommandName="someCommandInMyViewModel"/>
</coll:ArrayList>
I am using a listbox with a data template to show these items as follows.
<ListBox x:Name="lstNavigateTo" MinWidth="400" DockPanel.Dock="Top"
ItemsSource="{Binding Source={StaticResource MenuOptionsList}}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Style="{StaticResource horizontalListTemplate}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="5">
<Button Height="60" Width="60"
Command="{Binding Mode=OneWay, Path=CommandName}">
<Button.Content>
<Image Source="{Binding Path=Icon}" Grid.Row="0" />
</Button.Content>
</Button>
<TextBlock Text="{Binding Path=DisplayName}"
Width="100" TextAlignment="Center" Grid.Row="1" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My problem is that I am using the MVVM design pattern and cannot get the command bindings to work on the button click. Previously I would have managed the button click like this.
Command="{Binding someCommandInMyViewModel}"
That would work fine but when I try to bind a command to a property of an item in my collection the command will not fire.
Does anyone know how I can achieve this.
The CommandName property in your collection is of type String, whereas the Command property on Button is of type ICommand. In what way are you expecting WPF to resolve an ICommand from a String? You'll need to help it: either create a converter and use it in your binding, or change your CommandName property so that it contains an actual ICommand rather than a String.