How do I make a textbox visible and hidden with a checkbox? - c#

So I am trying to make my textbox invisible when a checkbox is not checked. Everything works fine untill I check the box and then uncheck it again. The textbox will stay visible.
private void chbon_Checked_1(object sender, RoutedEventArgs e)
{
if (cchbon.IsChecked == true)
{
txtshow.Visibility = System.Windows.Visibility.Visible;
}
if (chbon.IsChecked == false)
{
txtshow.Visibility = System.Windows.Visibility.Hidden;
}
}
This is the XAML for the Checkbox:
<CheckBox x:Name="chbon" Content="On" HorizontalAlignment="Left" Margin="175,84,0,0" VerticalAlignment="Top" Checked="chbon_Checked_1"/>
<TextBox x:Name="txtshow" HorizontalAlignment="Left" Height="23" Margin="272,82,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="29" Visibility="Hidden"/>

The event Checked does not fire when uncheck happens.
The event Unchecked is for that purpose.
... Checked="chbon_Checked" Unchecked="chbon_Unchecked"/>
and no need to monitor cchbon.IsChecked in code behind:
private void chbon_Checked(object sender, RoutedEventArgs e)
{
txtshow.Visibility = System.Windows.Visibility.Visible;
}
private void chbon_Unchecked(object sender, RoutedEventArgs e)
{
txtshow.Visibility = System.Windows.Visibility.Hidden;
}
Alternatively, you can do it via binding and a converter:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</Window.Resources>
...
<CheckBox x:Name="chbon"/>
<TextBox x:Name="txtshow" Visibility="{Binding ElementName=chbon, Path=IsChecked,
Converter={StaticResource BoolToVis}, FallbackValue=Hidden}"/>
Note that,
Once you managed this approach you may want to implement a custom converter since the built-in BooleanToVisibilityConverter returns Visible/Collapsed for True/False input (and not Visible/Hidden)

The Checked event handler will only hit when you check the checkbox, not uncheck it. You can also use the Unchecked handler in your XAML that would make the textbox hidden.
private void chbon_Unchecked(object sender, RoutedEventArgs e)
{
txtshow.Visibility = System.Windows.Visibility.Hidden;
}
private void chbon_Checked_1(object sender, RoutedEventArgs e)
{
txtshow.Visibility = System.Windows.Visibility.Visible;
}

when CheckBox goes to unchecked state, Unchecked event fires (simmetric to Checked). Add event handler to both of them.
<CheckBox x:Name="chbon"
Content="On"
HorizontalAlignment="Left"
Margin="175,84,0,0"
VerticalAlignment="Top"
Checked="chbon_Checked_1"
Unhecked="chbon_Checked_1"/>
private void chbon_Checked_1(object sender, RoutedEventArgs e)
{
txtshow.Visibility = cchbon.IsChecked ? Visibility.Visible : Visibility.Hidden;
}
It is common to use binding to boolean property to set Visibility of some element. There is a BooleanToVisibilityConverter in .NET, which returns Visible for true, and Collapsed for false. Collapsed is different from Hidden: Hidden element stil claims the space on the screen as if it was Visible.
There is a way to achieve everything in XAML using a Trigger:
<CheckBox x:Name="chbon" Content="On"
HorizontalAlignment="Left" Margin="175,84,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txtshow"
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="23" Width="29" Margin="272,82,0,0" TextWrapping="Wrap">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=chbon}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
<TextBox/>

Related

Event "unchecked" induced in the same way how "checked"(which work) dont work. Wpf

I dont understand why my event Unchecked isnt run. I have checkbox when I click it I change IsChecked = true in my all data in datagrid. When i click button again i change IsChecked on false.
When I click first time i run my event Checked.
<DataGrid x:Name="WordsDataGrid" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
AutoGenerateColumns="False" CellEditEnding="WordsDataGrid_CellEditEnding" Grid.RowSpan="2">
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="X" Width="10" Binding="{Binding Status}">
<DataGridCheckBoxColumn.CellStyle>
<Style>
<EventSetter Event="CheckBox.Checked" Handler="OnChecked"/>
<EventSetter Event="CheckBox.Unchecked" Handler="OnUnchecked"/>
</Style>
</DataGridCheckBoxColumn.CellStyle>
</DataGridCheckBoxColumn>
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Visibility="Visible" Height="16" Width="16" Click="UpdateOrAdd_Click">
<Button.Content>
<Image x:Name="KeyName" Source="{Binding ImageSource}" />
</Button.Content>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
private void All_Checked(object sender, RoutedEventArgs e)
{
words.ForEach(y => y.Status = true);
RefreshDataGridWords();
}
private void All_Unchecked(object sender, RoutedEventArgs e)
{
words.ForEach(y => y.Status = false);
RefreshDataGridWords();
}
private void OnChecked(object sender, RoutedEventArgs e)
{
...
}
private void OnUnchecked(object sender, RoutedEventArgs e)
{
...
}
For me it is the same, but second dont run event.
This work when I do that:
var itemsSource = WordsDataGrid.ItemsSource as IList<StatusWords>;
foreach (var item in itemsSource)
{
item.Status = true;
}
RefreshDataGridWords();
private void RefreshDataGridWords()
{
WordsDataGrid.ItemsSource = null;
WordsDataGrid.ItemsSource = words;
}

Can't access the events inside the GridViewColumn's Content

When I add an event to the ListViewItem,
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewMouseDown" Handler="listViewItem_MouseDown" />
</Style>
Then add another event in the content inside the GridViewColumn,
<GridViewColumn Header="Action">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image x:Name="imgEdit"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Width="40"
Height="40"
Tag="{Binding ProductBarcode}"
Cursor="Hand"
MouseDown="img_MouseDown">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="/Resources/edit_button.png" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Source" Value="/Resources/edit_button_hovered.png" />
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
I can't fire the event in the Image control. The one that is firing is the event in the ListViewItem. How to access the event in the Image control?
Here are the events:
private void img_MouseDown(object sender, MouseButtonEventArgs e)
{
switch ((sender as Image).Name)
{
case "imgEdit":
MessageBox.Show("EDIT");
break;
default:
break;
}
}
private void listViewItem_MouseDown(object sender, RoutedEventArgs e)
{
MessageBox.Show("ROW CLICKED");
}
The PreviewMouseDown event of the ListViewItem will always be raised before the MouseDown event of the Image. This is how routed events work: https://msdn.microsoft.com/en-us/library/ms742806(v=vs.110).aspx. PreviewMouseDown is a tunneling event and MouseDown is a bubbling event.
If you don't want to handle the PreviewMouseDown event when the Image is clicked you could check the type of the OriginalSource of the RoutedEventArgs and return immediately from the event handler if it is Image:
private void listViewItem_MouseDown(object sender, RoutedEventArgs e)
{
if (e.OriginalSource is Image)
return; // do nothing
MessageBox.Show("ROW CLICKED");
}
Try:
private void listViewItem_MouseDown(object sender, MouseButtonEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
MessageBox.Show("ROW CLICKED");
}));
}

Changing text in textblock to italicized on MouseEnter

I have a textblock that contains some non-italicized text. When the mouse enters the textblock, the text changes through the use of the code behind. I would like the code behind to also have the ability to change the text to italicized. This is what I have so far:
XAML:
<TextBlock x:Name="block1"
Background="Cyan"
Foreground="{StaticResource myBrush2}"
Grid.Column="0"
Grid.Row="0"
Height="30"
HorizontalAlignment="Center"
MouseEnter="TextBlock_MouseEnter"
MouseLeave="TextBlock_MouseLeave"
Padding="0,7,0,0"
Text ="Hover Me!"
TextAlignment="Center"
Width="100"/>
Code Behind (C#):
public void TextBlock_MouseEnter(object sender, MouseEventArgs e)
{
string blockName = ((TextBlock)sender).Name;
var block = sender as TextBlock;
if (block != null && blockName == "block1")
{
block.Text = "Yo! I'm TextBlock1";
}
}
I have looked into using System.Drawing and the use of FontStyle.Italic; although I was unsuccessful of actually making it work.
This is what XAML was made for
<TextBlock x:Name="block1"
Background="Cyan"
Foreground="{StaticResource myBrush2}"
Grid.Column="0"
Grid.Row="0"
Height="30"
HorizontalAlignment="Center"
MouseEnter="TextBlock_MouseEnter"
MouseLeave="TextBlock_MouseLeave"
Padding="0,7,0,0"
Text ="Hover Me!"
TextAlignment="Center"
Width="100">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontStyle" Value="Italic" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
But, if you really want to, here's an example of how you might implement that functionality from code-behind.
private void block1_MouseEnter(object sender, MouseEventArgs e)
{
SetFontStyle(FontStyles.Italic);
}
private void block1_MouseLeave(object sender, MouseEventArgs e)
{
SetFontStyle(FontStyles.Normal);
}
private void SetFontStyle(FontStyle style)
{
block1.FontStyle = style;
}

Open Buttons ContextMenu on Left Click

I have a button with a context menu, my requirements are to show the context menu on left click
The problem is that the <ContextMenu ItemsSource="{Binding LineItems}" isn't being updated/refresh when the context menu opens. However If i right click first, items are loaded fine
XAML
<Button x:Name="BtnMessageChannel" Click="BtnMessageChannel_Click" Grid.Row="0" Grid.Column="2" Height="23" Width="23" ToolTip="Message Channel" >
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding LineItems}" x:Name="CtxMessageChannel">
<ContextMenu.Resources>
<Image x:Key="img" Source="{Binding Icon}" x:Shared="false"/>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding DisplayName}"/>
<Setter Property="Icon" Value="{StaticResource img}">
</Setter>
</Style>
</ContextMenu.Resources>
</ContextMenu>
</Button.ContextMenu>
<Image Source="Images/mail_send.png" HorizontalAlignment="Left" Width="16" />
</Button>
Code Behind
private void BtnMessageChannel_Click(object sender, RoutedEventArgs e)
{
BtnMessageChannel.ContextMenu.GetBindingExpression(ContextMenu.ItemsSourceProperty)
.UpdateTarget();
BtnMessageChannel.ContextMenu.Visibility = Visibility.Visible;
BtnMessageChannel.ContextMenu.IsOpen = true;
}
Is there any easy solutions to this problem?
An easy solution is to update your button event handler to simulate a right click if the context menu is not currently open.
private void BtnMessageChannel_Click(object sender, RoutedEventArgs e)
{
if (!BtnMessageChannel.ContextMenu.IsOpen)
{
e.Handled = true;
var mouseRightClickEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Right)
{
RoutedEvent = Mouse.MouseUpEvent,
Source = sender,
};
InputManager.Current.ProcessInput(mouseRightClickEvent);
}
}

WPF Tab Control Prevent Tab Change

I'm trying to develop a system maintenance screen for my application in which I have several tabs each representing a different maintenance option i.e. maintain system users et cetera. Once a user clicks on edit/new to change a existing record I want to prevent navigating away from the current tab until the user either clicks save or cancel.
After some googling I've found a link http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/ which seemed to solve my problem, or so I thought.
I've tried implementing this, but my event never seems to fire. Below is my XAML.
<TabControl Name="tabControl">
<TabItem Header="Users">
<DockPanel>
<GroupBox Header="Existing Users" Name="groupBox1" DockPanel.Dock="Top" Height="50">
<StackPanel Orientation="Horizontal">
<Label Margin="3,3,0,0">User:</Label>
<ComboBox Width="100" Height="21" Margin="3,3,0,0"></ComboBox>
<Button Width="50" Height="21" Margin="3,3,0,0" Name="btnUsersEdit" Click="btnUsersEdit_Click">Edit</Button>
<Button Width="50" Height="21" Margin="3,3,0,0" Name="btnUsersNew" Click="btnUsersNew_Click">New</Button>
</StackPanel>
</GroupBox>
<GroupBox Header="User Information" Name="groupBox2">
<Button Content="Cancel" Height="21" Name="btnCancel" Width="50" Click="btnCancel_Click" />
</GroupBox>
</DockPanel>
</TabItem>
<TabItem Header="User Groups">
</TabItem>
</TabControl>
And this is my code
public partial class SystemMaintenanceWindow : Window
{
private enum TEditMode { emEdit, emNew, emBrowse }
private TEditMode _EditMode = TEditMode.emBrowse;
private TEditMode EditMode
{
get { return _EditMode; }
set
{
_EditMode = value;
}
}
public SystemMaintenanceWindow()
{
InitializeComponent();
var view = CollectionViewSource.GetDefaultView(tabControl.Items.SourceCollection);
view.CurrentChanging += this.Items_CurrentChanging;
}
void Items_CurrentChanging(object sender, CurrentChangingEventArgs e)
{
if ((e.IsCancelable) && (EditMode != TEditMode.emBrowse))
{
var item = ((ICollectionView)sender).CurrentItem;
e.Cancel = true;
tabControl.SelectedItem = item;
MessageBox.Show("Please Save or Cancel your work first.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void btnUsersNew_Click(object sender, RoutedEventArgs e)
{
EditMode = TEditMode.emNew;
}
private void btnUsersEdit_Click(object sender, RoutedEventArgs e)
{
EditMode = TEditMode.emEdit;
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
EditMode = TEditMode.emBrowse;
}
}
Apologies now if I'm being stupid, but for the life of me I cannot workout see why my event does not fire when the user clicks between tabs.
Thanks for all your help.
Emlyn
I've come up with a solution which suits my needs. Seems slightly backwards but compared to the other options I found, it seems nice and neat.
Basically I keep a private variable of the current tabIndex and on SelectionChanged event of the TabControl, I'm doing some checks and set the TabControl.SelectedIndex back to this value if the user is not in browse mode.
private void tabControl_SelectionChanged(object sender,
System.Windows.Controls.SelectionChangedEventArgs e)
{
if (e.OriginalSource == tabControl)
{
if (EditMode == TEditMode.emBrowse)
{
_TabItemIndex = tabControl.SelectedIndex;
}
else if (tabControl.SelectedIndex != _TabItemIndex)
{
e.Handled = true;
tabControl.SelectedIndex = _TabItemIndex;
MessageBox.Show("Please Save or Cancel your work first.", "Error",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
I was struggling with this too. Just got it working by simply adding the
IsSynchronizedWithCurrentItem="True"
setting to the TabControl. Worked like a charm after that.
According to this post
https://social.msdn.microsoft.com/Forums/vstudio/en-US/d8ac2677-b760-4388-a797-b39db84a7e0f/how-to-cancel-tabcontrolselectionchanged?forum=wpf
this worked for me:
<TabControl>
<TabControl.Resources>
<Style TargetType="TabItem">
<EventSetter Event="PreviewMouseLeftButtonDown"
Handler="OnPreviewMouseLeftButtonDown"/>
</Style>
</TabControl.Resources>
<TabItem Header="Tab1"/>
<TabItem Header="Tab2"/>
</TabControl>
private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.Source is TabItem) //do not handle clicks on TabItem content but on TabItem itself
{
var vm = this.DataContext as MyViewModel;
if (vm != null)
{
if (!vm.CanLeave())
{
e.Handled = true;
}
}
}
}
Josh is using tab.ItemsSource. You are using tab.Items.SourceCollection. This might be the problem.
Or implement it yourself...
public delegate void PreviewSelectionChangedEventHandler(object p_oSender, PreviewSelectionChangedEventArgs p_eEventArgs);
public class PreviewSelectionChangedEventArgs
{
internal PreviewSelectionChangedEventArgs(IList p_lAddedItems, IList p_lRemovedItems)
{
this.AddedItems = p_lAddedItems;
this.RemovedItems = p_lRemovedItems;
}
public bool Cancel { get; set; }
public IList AddedItems { get; private set; }
public IList RemovedItems { get; private set; }
}
public class TabControl2: TabControl
{
public event PreviewSelectionChangedEventHandler PreviewSelectionChanged;
private int? m_lLastSelectedIndex;
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
// déterminer si on doit annuler la sélection
PreviewSelectionChangedEventArgs eEventArgs = new PreviewSelectionChangedEventArgs(e.AddedItems, e.RemovedItems);
if (m_lLastSelectedIndex.HasValue)
if (PreviewSelectionChanged != null)
PreviewSelectionChanged(this, eEventArgs);
// annuler (ou pas) la sélection
if (eEventArgs.Cancel)
this.SelectedIndex = m_lLastSelectedIndex.Value;
else
m_lLastSelectedIndex = this.SelectedIndex;
}
}
I am starting to grasp XAML so I hope I didn't miss your point. I had the same problem and for me this worked best.
In XAML I define a Style that toggles the ReadOnly State
<!-- prevent the tab from being changed while editing or adding a physician -->
<Style BasedOn="{StaticResource {x:Type TabControl}}"
TargetType="{x:Type TabControl}" x:Key="InactivateTabControl">
<!-- <Setter Property="IsEnabled" Value="True" /> -->
<Style.Triggers>
<DataTrigger Binding="{Binding PhysicianTypeTabAreLocked}" Value="False">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding PhysicianTypeTabAreLocked}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
<TabControl Grid.Row="1" Grid.Column="0" Margin="0, 10, 0, 0"
x:Name="PhysicianTypesTabControl"
SelectedIndex="{Binding PhysicianTypeSelectedTabIndex, Mode=TwoWay}"
Style="{StaticResource InactivateTabControl}">
<!-- rest here ....-->
<TabControl/>
In the viewmodel I have a property
private EditingState _PhysicianEditingState;
public EditingState PhysicianEditingState
{
get { return _PhysicianEditingState; }
set
{
_PhysicianEditingState = value;
PhysicianTypeTabAreLocked = (PhysicianEditingState != EditingState.NotEditing);
NotifyPropertyChanged("PhysicianTypeTabAreLocked");
}
}
Hope this helps.
The thing that finally worked really well for me was to disable the "TabItems" when I didn't want the user to be able to select them, and then to enable them when I did want them too.
<TabControl IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Pages}" SelectedItem="{Binding SelectedPage}" TabStripPlacement="Left">
<TabControl.Resources>
<Style BasedOn="{StaticResource {x:Type TabItem}}" TargetType="TabItem">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}" />
</Style>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding StepName}" Foreground="{DynamicResource TabActiveSelectedFont}" />
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
This allowed my view model (in this case my pages) to be able to determine when they allowed the user to move to the next page. So When they were done with the current page I would "enable" the next page so they could click on it to continue.
You could simply set the TabItems' IsEnabled property to false which prevents navigation/activation but is not disabling the tabs' content, until your condition (save/cancel) is met.

Categories