ShowDialog() can be bypassed? - c#

I accidentally found this while working with my project, but I was able to reproduce this in a base project:
I open a MainWindow, then with ShowDialog a child window, Owner set to the Main. When I click on the Main, the Child starts to flash, then I start clicking between the Main and the Child very fast, and sometimes the Main gets the focus, then I able to open another Child window.
MainWindow:
<Window x:Class="WpfShowDialog.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="300" WindowStartupLocation="CenterScreen" >
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" >
<TextBlock Text="MainWindow" Margin="10" />
<Button Content="Open child" Margin="10" Click="Button_Click" />
</StackPanel>
</Window>
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var childWindow = new ChildWindow()
{
Owner = this
};
childWindow.ShowDialog();
}
}
ChildWindow:
<Window x:Class="WpfShowDialog.ChildWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ChildWindow" Height="150" Width="200" WindowStartupLocation="CenterOwner">
<Grid>
<TextBlock Text="ChildWindow" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Window>
Code behind:
public partial class ChildWindow : Window
{
public ChildWindow()
{
InitializeComponent();
}
}
I click on between these red circles:
Is this some kind of bug, or I miss something?

Related

Focus Textbox across multiple Usercontrols controlling from MainWindow

i have two usercontrols which is bound in MainWindow. What i want when MainWindow is Loaded, textbox1 which is in usercontrol1 should be focused automatically, and when i hit down arrow from keyboard textbox2 which is in usercontrol2 should be focused. And again on up arrow focus textbox1.
Below is MainWindow's xaml code`
<Window x:Class="FocusTextboxesFromMain.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:FocusTextboxesFromMain" Loaded="Window_Loaded"
mc:Ignorable="d"
Title="Focus Textboxes Testing" Height="450" Width="800">
<Grid>
<StackPanel>
<local:UserControl1/>
<local:UserControl2/>
</StackPanel>
</Grid>
Below is Usercontrol1's xaml code`
<UserControl
x:Class="FocusTextboxesFromMain.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FocusTextboxesFromMain"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Width="800"
Height="200"
mc:Ignorable="d">
<Grid Background="Red">
<TextBlock
FontSize="50"
Foreground="White"
Text="UserControl1" />
<TextBox
x:Name="textbox1"
Width="200"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="25" />
</Grid>
and below is Usercontrol2's xaml code`
<UserControl
x:Class="FocusTextboxesFromMain.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FocusTextboxesFromMain"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Width="800"
Height="200"
mc:Ignorable="d">
<Grid Background="Green">
<TextBlock
FontSize="50"
Foreground="White"
Text="UserControl2" />
<TextBox
x:Name="textbox2"
Width="200"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="25" />
</Grid>
please note that i want all my logic in MainWindow Class, MvvM should not be involved
namespace FocusTextboxesFromMain
{
using System.Windows;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Focus textbox1 of usercontrol1
}
// on down arrow then Focus textbox2 of usercontrol2
// and again on up arrow then Focus textbox1 of usercontrol1
}
}
sorry for bad explanation, thanks in advance
You can find what you are looking for in the answer of this question:
Moving to next control on Enter keypress in WPF
Just follow the code and create related event
public MainWindow()
{
InitializeComponent();
this.PreviewKeyDown += new KeyEventHandler(txtFirst_KeyDown);
this.PreviewKeyDown += new KeyEventHandler(txtSecond_KeyDown);
}
private void txtFirst_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Down)
{
txtSecond.Focus();
}
}
private void txtSecond_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Up)
{
txtFirst.Focus();
}
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
txtFirst.Focus();
}

How to reach and-, name own FrameworkElement from xaml

I have the following, working code:
<Window x:Class="GemTowerDefense.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GemTowerDefense"
mc:Ignorable="d"
Title="Gem Tower Defense" Height="670" Width="800"
Loaded="Window_Loaded">
<Window.Resources>
<local:GameControl x:Key="MyGameControl"/>
</Window.Resources>
<Grid>
<Border Background="Gray" Height="600" Width="600" Margin="3,26,189,3">
<local:GameControl/>
</Border>
</Grid>
</Window>
Here you can see that I have the "local:GameControl" duplicated. This is because I only had the GameControl inside the "Grid" and the "Border". Everything worked fine, I implemented OnRender inside GameControl, it draws out everything I want it to.
My problem is, that I want this local:GameControl to interact with the MainWindow's buttons:
<Button Click="Life_Button_Click" Content="Buy 1 Life" HorizontalAlignment="Left" Margin="608,26,0,0" VerticalAlignment="Top" Width="170"/>
<Button Click="Upgrade_Button_Click" Content="Upgrade Chances" HorizontalAlignment="Left" Margin="608,51,0,0" VerticalAlignment="Top" Width="170"/>
<Button Click="Place_Button_Click" Content="Place Gems" HorizontalAlignment="Left" Margin="608,156,0,0" VerticalAlignment="Top" Width="170"/>
So I added this inside "Grid". But inside the Button Click Event Handlers, I don't know how to reach GameControl.
What I want to do is something like this:
public partial class MainWindow : Window
{
GameControl control { get; set; }
private void Life_Button_Click(object sender, RoutedEventArgs e)
{
control.BuyLife();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
control = Application.Current.MainWindow.Resources["MyGameControl"] as GameControl;
}
}
How can I achieve this to work?
This doesn't work obviously, because I cannot name GameControl with an x:Key, only if I add it as a resource, but then I dont know how to refer to it as a FrameworkElement in the xaml code.
Give the control an x:Name:
<Border Background="Gray" Height="600" Width="600" Margin="3,26,189,3">
<local:GameControl x:Name="control" />
</Border>
You can then access it in the code-behind:
private void Life_Button_Click(object sender, RoutedEventArgs e)
{
control.BuyLife();
}

having a custom popup window on top of mainwindow makes mainwindow not to come to topmost

I used InteractionRequestTrigger and Popupwindowaction of prism to raise custom popup window and it is not a model window, but having a custom popup window on top of mainwindow makes mainwindow not to come to top when non-model popup window is there and main window is clicked by user, Any idea how to resolve this ?
MainWindowView
<Window x:Class="UsingPopupWindowAction.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:prism="http://prismlibrary.com/"
xmlns:views="clr-namespace:UsingPopupWindowAction.Views"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="350" Width="500">
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding NotificationRequest}">
<prism:PopupWindowAction IsModal="False" CenterOverAssociatedObject="True" >
<prism:PopupWindowAction.WindowContent>
<views:CustomePopup/>
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
<StackPanel>
<Button Margin="5" Content="Raise Custome Popup" Command="{Binding NotificationCommand}" />
<TextBlock Text="{Binding Title}" Margin="25" HorizontalAlignment="Center" FontSize="24" />
</StackPanel>
</Window>
MainWindowViewModel
namespace UsingPopupWindowAction.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private string _title = "MainWindow";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public InteractionRequest<INotification> NotificationRequest { get; set; }
public DelegateCommand NotificationCommand { get; set; }
public MainWindowViewModel()
{
NotificationRequest = new InteractionRequest<INotification>();
NotificationCommand = new DelegateCommand(RaiseNotification);
}
void RaiseNotification()
{
NotificationRequest.Raise(new Notification { Content = "Notification Message", Title = "Custome Popup" }, r => Title = "Notified");
}
}
}
CustomePopupView
<UserControl x:Class="UsingPopupWindowAction.Views.CustomePopup"
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:local="clr-namespace:UsingPopupWindowAction.Views"
Height="400" Width="400">
<Grid>
<TextBlock Text="Please click mainwindow to get it to top of me" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</UserControl>

CommandParameter is always NULL

I want to implement a simple Close Button in a WPF Window. The Window basically looks like this:
<Window x:Class="MyApplication.MainWindow"
xmlns=""....
...."
Title="MainWindow" WindowState="Maximized" WindowStartupLocation="CenterScreen" x:Name="mainWindow">
<DockPanel LastChildFill="True">
<Ribbon DockPanel.Dock="Top">
<Ribbon.ApplicationMenu>
<RibbonApplicationMenu SmallImageSource="Resources/menu_16x16.png">
<RibbonApplicationMenu.FooterPaneContent>
<RibbonButton Label="Beenden"
Command="{Binding CmdCloseApp}"
CommandParameter="{Binding ElementName=mainWindow}"
SmallImageSource="Resources/ende_16x16.png"
HorizontalAlignment="Right"/>
</RibbonApplicationMenu.FooterPaneContent>
</RibbonApplicationMenu>
</Ribbon.ApplicationMenu>
</Ribbon>
</DockPanel>
</Window>
DataContext of this Window ist set in it's Code-behindt to an instance of MainWindowViewModel
MainWindowViewModel:
public class MainWindowViewModel
{
public ICommand CmdCloseApp { get; set; }
public MainWindowViewModel()
{
CmdCloseApp = new RelayCommand<Window>(CloseApp);
}
public void CloseApp(Window w)
{
w.Close();
}
}
In CloseAppw is always null. Alle the other commands with string paramters, etc.. work perfectly - my only problem is that i don't get the window element does not find a way to my viewmodel.
thanks for your help!
EDIT
I am so sorry, i tried it with a simple button and it worked - The problem only occurs with RibbonButton
Edit: After your change to application menu RibbonButton your issue is that Microsoft RibbonControlLibrary uses a popup menu to hold the button, and the MainWindow is not part (parent of) of the popup menu's visual tree, so your ElementName binding can not find the "mainWindow" window, so it assigns null to CommandParameter
You could use static Application.Current to get MainWindow, then it will work.
NB! MainWindow is the Application property name, not the name of your window
<Window x:Class="WpfRelayCommandParameter.MainWindow"
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:wpfRelayCommandParameter="clr-namespace:WpfRelayCommandParameter"
xmlns:ribbon="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance wpfRelayCommandParameter:MainWindowViewModel}"
Title="MainWindow" Height="350" Width="525"
x:Name="mainWindow">
<DockPanel LastChildFill="True">
<DockPanel LastChildFill="True">
<ribbon:Ribbon DockPanel.Dock="Top">
<ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonApplicationMenu SmallImageSource="Resources/AppMenu.png">
<ribbon:RibbonApplicationMenu.FooterPaneContent>
<ribbon:RibbonButton Label="Beenden"
Command="{Binding CmdCloseApp}"
CommandParameter="{Binding MainWindow, Source={x:Static Application.Current}}"
SmallImageSource="Resources/Exit.png"
HorizontalAlignment="Right" Click="ButtonBase_OnClick"/>
</ribbon:RibbonApplicationMenu.FooterPaneContent>
</ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
</ribbon:Ribbon>
</DockPanel>
</DockPanel>
Personally I prefer callbacks to the window to go through an interface that can be custom to your view model needs, and can be mocked in unit tests:
<Window x:Class="WpfRelayCommandParameter.MainWindow"
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:wpfRelayCommandParameter="clr-namespace:WpfRelayCommandParameter"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance wpfRelayCommandParameter:MainWindowViewModel}"
Title="MainWindow" Height="350" Width="525"
x:Name="mainWindow">
<Grid>
<Button Content="Close Window"
Command="{Binding CmdCloseApp}"
VerticalAlignment="Top"
HorizontalAlignment="Left" />
</Grid>
Code
public partial class MainWindow : Window, IMainWindow
{
public MainWindow()
{
DataContext = new MainWindowViewModel(this);
InitializeComponent();
}
}
public interface IMainWindow
{
void Close();
}
public class MainWindowViewModel
{
private readonly IMainWindow _mainWindow;
public MainWindowViewModel() : this(null)
{
// Design time
}
public MainWindowViewModel(IMainWindow mainWindow)
{
_mainWindow = mainWindow;
CmdCloseApp = new RelayCommand(CloseApp);
}
public ICommand CmdCloseApp { get; set; }
public void CloseApp(object parameter)
{
_mainWindow.Close();
}
}
Note possible issues with type and null for CanExecute CanExecute on RelayCommand

How can I bind a ListBox control to a List in WPF?

I want to create a 2 way bind between a listbox and a .NET list.
In my GUI, I have a listbox, a textbox and add and remove buttons.
The listbox displays cars, and my goal is to create a two-way bind between the .Net car list and the listbox: when the user enters a car into the textbox, it gets updated only in the .Net list, and the listbox is updated automatically.
When the user press the GUI "remove" button, a car gets removed from the GUI and the .Net list is updated automatically.
I've started to write the xaml code, but figured that I don't actually know how to do the binding on both sides (c# and xaml):
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="369" Loaded="Window_Loaded">
<Window.Resources>
<ObjectDataProvider x:Key="carsData"
ObjectType="{x:Type c:Window1}" />
</Window.Resources>
<Grid Width="332">
<ListBox Margin="10,62,0,100" Name="myListBox" HorizontalAlignment="Left" Width="120" ItemsSource="{Binding Source={StaticResource CarsData}}"/>
<Button Height="23" Margin="66,0,0,65" Name="addBtn" VerticalAlignment="Bottom" Click="addBtn_Click" HorizontalAlignment="Left" Width="64">add</Button>
<TextBox Margin="10,0,0,64.48" Name="myTextBox" Height="23" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="47" />
<Button Height="23" Margin="66,0,0,33" Name="removeButton" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="64" Click="removeButton_Click">Remove</Button>
</Grid>
</Window>
There is my c# code:
public partial class Window1 : Window
{
MyModel listMgr;
ObservableCollection<Car> carList;
public Window1()
{
InitializeComponent();
listMgr = new MyModel();
}
private void addBtn_Click(object sender, RoutedEventArgs e)
{
listMgr.add(new Car(0, myTextBox.Text, 2011));
}
private void removeButton_Click(object sender, RoutedEventArgs e)
{
//myListBox.Items.RemoveAt(0);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
carList = listMgr.getList();
myListBox.DataContext = carList;
//secondListBox.DataContext = carList;
}
}
This is a quick version, you'll need to add code to check the car is selected, etc.
To see your Car data you'll need to define a data template. In the example it's just a simple name, but you can change the text colour, font size, add more fields, etc.
It's best to work on the list when adding / removing cars, not on the ListBox directly.
XAML:
<Window x:Class="cars.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="car_template" DataType="Car">
<TextBlock Text="{Binding name}"/>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox x:Name="cars_box" Margin="5" ItemsSource="{Binding}" ItemTemplate="{StaticResource car_template}"/>
<TextBox x:Name="new_car_box" Margin="5"/>
<Button Content="add" Click="add_car" Margin="5"/>
<Button Content="delete" Click="delete_car" Margin="5"/>
</StackPanel>
C#:
using System.Collections.ObjectModel;
using System.Windows;
public partial class MainWindow : Window
{
ObservableCollection<Car> cars = new ObservableCollection<Car>();
public MainWindow()
{
InitializeComponent();
cars.Add(new Car("Volvo"));
cars.Add(new Car("Ferrari"));
cars_box.DataContext = cars;
}
private void add_car(object sender, RoutedEventArgs e)
{
cars.Add(new Car(new_car_box.Text));
}
private void delete_car(object sender, RoutedEventArgs e)
{
cars.Remove((cars_box.SelectedItem as Car));
}
}
public class Car
{
public string name { get; set; }
public Car(string _name)
{
this.name = _name;
}
}

Categories