How to open a WPF Popup when RadioButton checked? - wpf

I have a RadioButton and a Popup. I want to open Popup when checked RadioButton and close Popup when LostFocus of it, without unchecked RadioButton.
I use this code.
<StackPanel>
<RadioButton x:Name="RadioButtonSave" IsChecked="{Binding IsSave}">Save</RadioButton>
<RadioButton x:Name="RadioButtonNotSave" LostFocus="RadioButtonNotSave_OnLostFocus" IsChecked="{Binding IsSave,Converter={StaticResource ToNegativeConverter}}">Not Save</RadioButton>
</StackPanel>
<Popup x:Name="Popup" IsOpen="{Binding IsChecked,ElementName=RadioButtonNotSave}" StaysOpen="True" Placement="Left" PlacementTarget="{Binding ElementName=RadioButtonNotSave}"></Popup>
private void RadioButtonNotSave_OnLostFocus(object sender, RoutedEventArgs e)
{
Popup.IsOpen = false;
}
It is open popup when checked but when lostfocuse unchecked radiobutton.
I set Mode=OneWay for IsOpen , it is open popup and don't unchecked radionButton in lost focuse, but it worked for one time.

Here is a way of doing it only in XAML:
<Window x:Class="RadioButtonAndPopup.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">
<Grid>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type RadioButton}">
<EventSetter Event="Click" Handler="EventSetter_OnHandler"/>
</Style>
</StackPanel.Resource>
<RadioButton x:Name="RadioBtn" Content="TestPopup"/>
<Popup x:Name="myPopup" IsOpen="{Binding IsChecked, ElementName=RadioBtn, Mode=OneWay}" Placement="Mouse" StaysOpen="False">
<Border Background="LightBlue">
<TextBlock>Popup</TextBlock>
</Border>
</Popup>
</StackPanel>
</Grid>
Setting StaysOpen false, you will be able to close the Popup by clicking anywhere outside it.
Update 1:
Add this in the StackPanel.Resources and name your Popup.
<Style TargetType="{x:Type RadioButton}">
<EventSetter Event="Click" Handler="EventSetter_OnHandler"/>
</Style>
And this will be added to codebehind:
private void EventSetter_OnHandler(object sender, RoutedEventArgs e)
{
myPopup.IsOpen = true;
}
So now the Popup will be opened on that Click event and not from the IsChecked binding.

Try this instead:
private void RadioButtonNotSave_OnLostFocus(object sender, RoutedEventArgs e)
{
IsChecked = false;
}

Related

DragMove() will make the Border with cornerRadius lose its mouseover trigger state?

I have created a borderless window with rounded corners, and added the drag event and a trigger to it. Here is the simple code:
<Window x:Class="DebugTest.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:DebugTest"
mc:Ignorable="d" Height="200" Width="200"
AllowsTransparency="True" WindowStyle="None" Background="Transparent">
<Border x:Name="MainBorder" CornerRadius="15" Background="White" BorderBrush="Black" BorderThickness="1">
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MainBorder,Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Button Content="x" HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="5" Height="20" Width="20" Click="Button_Click"/>
</Grid>
</Border>
</Window>
public MainWindow()
{
InitializeComponent();
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
this.DragMove();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
But when I run the exe file, click on the blank area within the window, the button will appear very obvious flickering situation.
Strangely enough, this situation hardly occurs when debugging in Visual Studio instead of double click the file, and it also doesn't happen while CornerRadius="0".
It looks like it lost the mouseover trigger on click, but I can't think of any good way to avoid flicker appearing, and to satisfy the need for both with rounded corners, draggable, and with trigger.
Well, although I don't know why only rounded corners would cause DragMove() to trigger the MouseLeave event, I circumvented this with background code instead of using xaml trigger.
<Border x:Name="MainBorder" CornerRadius="15" Background="White"
BorderBrush="Black" BorderThickness="1"
MouseEnter="MainBorder_MouseEnter" MouseLeave="MainBorder_MouseLeave">
<Grid Visibility="Hidden" x:Name="TriggerBorder">
<Button Content="x" HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="5" Height="20" Width="20" Click="Button_Click"/>
</Grid>
</Border>
bool dragMoving = false;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
dragMoving = true;
this.DragMove();
dragMoving = false;
}
private void MainBorder_MouseEnter(object sender, MouseEventArgs e)
{
TriggerBorder.Visibility = Visibility.Visible;
}
private void MainBorder_MouseLeave(object sender, MouseEventArgs e)
{
if (dragMoving) return;
TriggerBorder.Visibility = Visibility.Hidden;
}
Seems to work fine.

Empty textbox on mousclick in combination with language change in WPF

I have a textbox with a default text. When I focus the textbox it is cleared so I can write, and if I unfocus without writing anything the default text reappears.
I also have two radiobuttons for selecting the language. The languages are provided as xaml resourcefiles and the default text in the textbox is connected to that using DynamicResource.
My problem is that the language change only work as long as I haven't focused the textbox. If I focus the textbox and then unfocus it without changing anything, the textbox no longer changes language.
I'm guessing that is because once it's changed (cleared) it's no longer linked to the dynamic resource, because WPF considers my onfocus changes as user input, but I can't figure out how to get around that and make it change language even if I've clicked the textbox.
The second textbox don't have any focus behaviour and in that one the language change works as it should, i.e. it changes the language as long as I haven't actually written something.
MainWindow xaml:
<Window x:Class="Textbox_langauge_buggseek.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:Textbox_langauge_buggseek"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox x:Name="TextBox" HorizontalAlignment="Left" Height="46" Margin="84,55,0,0" TextWrapping="Wrap" Text="{DynamicResource ResourceKey=TB}" VerticalAlignment="Top" Width="334" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus"/>
<TextBox x:Name="TextBox_Copy" HorizontalAlignment="Left" Height="46" Margin="84,123,0,0" TextWrapping="Wrap" Text="{DynamicResource ResourceKey=TB}" VerticalAlignment="Top" Width="334"/>
<RadioButton x:Name="En" Content="En" GroupName="Lang" HorizontalAlignment="Left" Margin="391,216,0,0" VerticalAlignment="Top" Checked="En_Checked" IsChecked="True"/>
<RadioButton x:Name="Se" Content="Se" GroupName="Lang" HorizontalAlignment="Left" Margin="391,234,0,0" VerticalAlignment="Top" Checked="Se_Checked"/>
</Grid>
</Window>
MainWindows cs:
using System;
using System.Windows;
using System.Windows.Controls;
namespace Textbox_langauge_buggseek
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
SetLanguageDictionary();
}
//*****************************************************************************************
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
TextBox box = sender as TextBox;
box.Text = box.Text == (string)this.Resources["TB"] ? string.Empty : box.Text;
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
TextBox box = sender as TextBox;
box.Text = box.Text == string.Empty ? (string)this.Resources["TB"] : box.Text;
}
//*****************************************************************************************
private void En_Checked(object sender, RoutedEventArgs e)
{
SetLanguageDictionary("En");
}
private void Se_Checked(object sender, RoutedEventArgs e)
{
SetLanguageDictionary("Se");
}
//*****************************************************************************************
private void SetLanguageDictionary(string language = "En")
{
ResourceDictionary dict = new ResourceDictionary();
switch (language)
{
case "Se":
dict.Source = new Uri("..\\Resources\\Se.xaml", UriKind.Relative);
break;
default:
dict.Source = new Uri("..\\Resources\\En.xaml", UriKind.Relative);
break;
}
this.Resources.MergedDictionaries.Add(dict);
}
}
}
En language xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="TB">Text in the TextBox!</system:String>
</ResourceDictionary>
Se language xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="TB">Text i textrutan!</system:String>
</ResourceDictionary>
Yes, when you set TextBox.Text in codebehind, the text does not know anymore that it has to take a value from the Rersource. To avoid it you can change the text using pure XAML, with Triggers.
Remove TextBox's event handlers and add a style like this:
<TextBox x:Name="TextBox" HorizontalAlignment="Left" Height="46" Margin="84,55,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="334">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Text" Value="" />
</Trigger>
<Trigger Property="IsFocused" Value="false">
<Setter Property="Text" Value="{DynamicResource ResourceKey=TB}" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Change image of a templated button in wpf

I have a templated wpf button. I have to change the image at runtime.
xaml code:
<Window.Resources>
<Image x:Key="imgPlay" Source="Media/Knob Play.png"></Image>
<Image x:Key="imgStop" Source="Media/Knob Red.png"></Image>
<ControlTemplate x:Key="custom-button" TargetType="Button">
<Grid x:Name="btn_image">
<!--<Grid.Background>
<ImageBrush ImageSource="Media/Knob Red.png"></ImageBrush>
</Grid.Background>-->
<!--<Image Source="Media/Knob Red.png"></Image>-->
</Grid>
</ControlTemplate>
</Window.Resources>
button i need to change:
<Button Name="start" Template="{DynamicResource custom-button}" HorizontalAlignment="Left" Margin="147,67,0,0" VerticalAlignment="Top" Width="37" Height="30" Click="Start_Click">
<DynamicResource ResourceKey="imgStop"></DynamicResource>
</Button>
codebehind:
private void Start_Click(object sender, RoutedEventArgs e)
{
if (sw.IsRunning)
{
start.Content = FindResource("imgStop");
sw.Stop();
dt.Stop();
}
else
{
sw.Start();
dt.Start();
start.Content = FindResource("imgPlay");
}
}
tried many solutions in SO and net .Nothing worked.
Maybe you can get an inspiration from this...
Resource
<Window.Resources>
<ControlTemplate x:Key="option1" TargetType="Button">
<TextBlock Foreground="Red">ClickMe</TextBlock>
</ControlTemplate>
<ControlTemplate x:Key="option2" TargetType="Button">
<TextBlock Foreground="Green">Template is changed</TextBlock>
</ControlTemplate>
</Window.Resources>
XAML:
<Grid Width="100" Height="100">
<Button Name="theButton" Click="OnClick" Template="{StaticResource option1}"/>
</Grid>
Code behind:
private void OnClick(object sender, RoutedEventArgs e)
{
this.theButton.Template = (ControlTemplate)FindResource("option2");
}

How to make my control focusable?

I have a control
public class FocusTestControl : Control {
public FocusTestControl() {
DefaultStyleKey = typeof(FocusTestControl);
}
}
Here is it's default style
<Style
TargetType="local:FocusTestControl">
<Setter
Property="Focusable"
Value="True" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border
Background="AliceBlue" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I put this control on a window:
<Window
x:Class="MakeWpfControlFocusable.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MakeWpfControlFocusable"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition
Height="35" />
</Grid.RowDefinitions>
<local:FocusTestControl />
<StackPanel
Grid.Row="1"
Orientation="Horizontal">
<TextBlock
Text="Focused element: " />
<TextBlock
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=KeyboardFocusedElement}" />
<TextBox
Text="Text" />
</StackPanel>
</Grid>
But clicking on control doesn't make it focused (I mean KebordFocus)
Actually, my task is handle the KeyDown and KeyUp events. But it is impossible when element has no keybord focus.
Keybord focus can be set by pessing Tab keyboard key. But is is not set when click on the control. I've subscribed to the MouseDown event and set focus manually in the handler.
public class FocusTestControl : Control, IInputElement {
public FocusTestControl() {
DefaultStyleKey = typeof(FocusTestControl);
MouseDown += FocusTestControl_MouseDown;
}
void FocusTestControl_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
Keyboard.Focus(this);
}
}

2 states click - listbox item WPF

I have a ListboxItem with a checkbox in its template. When I click the checkbox, a section of the template gets visible. That works ok.
I am trying to simulate the same behaviour by clicking the item itself making it expand/collapse the respective section. It should always negate the current state of the item(expanded/collapsed)
I am using C#/WPF
<Grid x:Name="gridExpanded"
HorizontalAlignment="Stretch"
Margin="8"
Grid.RowSpan="1"
Width="Auto"
Height="Auto"
Visibility="{Binding IsChecked, Converter={StaticResource booleanToVisibilityConverter}, ElementName=checkBox}" />
It sounds like you are actually looking for the Expander control. This allows you to specify a header and content, and clicking on the header will toggle the visibility of the content
By WPF ListBox does not change CheckBox state when the corresponding label is clicked.
To solve this,
1) Add a IsVisibleFlag property to the item model
2) Add a handler for the PreviewMouseLeftButtonDown event of the item
3) In the handler use ItemContainerGenerator.ContainerFromItem to update the visibility flag on click
4) Associate the visibility of your template section with the IsVisibleFlag (or with the checkBox state).
The ItemModel:
publibc class MyItemModel : INotifyPropertyChanged
{
private bool _isVisibleFlag;
public bool IsVisibleFlag
{
get { return _isVisibleFlag; }
set
{
if (_isVisibleFlag != value)
{
_isVisibleFlag = value;
OnPropertyChanged(() => IsVisibleFlag);
}
}
}
// ItemText property goes here (I ommited it to save space)
}
In XAML:
<Window
<!--generated x:Class and xmlns goes here (I ommited them to save space) -->
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<Window.Resources>
<Style TargetType="ListBoxItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox Name="chkVisible" Grid.Column="0" IsChecked="{Binding IsVisibleFlag}" />
<TextBlock Grid.Column="1" Text="{Binding ItemText}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox Name="MyListBox" ItemsSource="{Binding AddableWidgets}" />
</Grid>
</Window>
In code:
private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
for (int i = 0; i < MyListBox.Items.Count; i++)
{
object yourObject = MyListBox.Items[i];
ListBoxItem lbi = (ListBoxItem)MyListBox.ItemContainerGenerator.ContainerFromItem(yourObject);
if (lbi.IsFocused)
{
MyItemModel w = (MyItemModel)MyListBox.Items[i];
w.IsVisibleFlag = !w.IsVisibleFlag;
e.Handled = true;
}
}
}

Resources