Enabling a specific button inside a disabled grid - wpf

I got a button inside a grid that contains many other buttons and controls such as this
<Grid IsEnabled="false">
<Grid.ColumnsDefinition>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnsDefinition>
<Button Content="Run"/>
<Button Grid.Column="1" Content="Test"/>
<Button Grid.Column="2" Content="Cancel" IsEnabled="true"/>
</Grid>
As you can see the grid is disabled, but the cancel button inside it is supposed to be enabled.
The problem I'm having is that even though I set the inside button to be enabled, it stays disabled, probably because its parent is disabled.
Is there any way to override this behavior and force the button to be enabled?
I'm using it for a case where there's a long process running in the background, so all the UI actions except for cancelling the process should be disabled.
Thanks!

No. Setting IsEnabled property to false leads to disabling all the nested visual elements. One should think of element's contents as parts of its being. Disabling the element means disabling all of its parts.
The easiest workaround is to change the markup to meet your needs. I would rather bring the Cancel button out of this Grid so it's never affected by IsEnabled property of the Grid

Related

Button/Image Switch resource using click, MouseEnter and MouseLeave

I'm trying to change an image using events like Click, MouseEnter and MouseLeave. In first place I tried to do it with Buttons in order to have "Click" event too, but I don't know how to remove that lightblue background that appears by default when I put the mouse over the button with a png background.
After this, I tried to use , setting the resource image.png in its Source.
The main problem is that I don't know what to do in code-behind to change between Image Resources in order to change the Source of the control.
I want to know too if I can use a "Click Event" with an control
Update1:
Ok, I tried it by using Binding
For now I think its solved, but I have another problem.
I don't know exactly how to remove that "border". I tried to put the borderbrush property of the buttons to 0, but it seems to be another property or another control.
UI
Thanks.
You can put an image as the content of a button, and add an Click event to that Button. This way, an event gets called when you press the button.
<Button Margin="0,10" Name="mainButton" Click="mainButton_Click">
<Button.Content>
<Image Source="C:/reference-to-image" Height="30"/>
</Button.Content>
</Button>
In the background you can than change the Picture.
This question shows how to do that in the background.
WPF Image UriSource and Data Binding using http:\\ URL
PS. If you want to change the behavior of controls on certain events things like pressing the left mouse button on it, you have to overwrite the event triggers using
<Style TargetType="TextBlock">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
...
Hope this helps.
UPDATE
You can set the BorderThickness to 0 and than set the Value of the Padding Property to 0. The Button Control has a predefined padding value, which makes it look like it has a border.
Padding is the space inside the control and the content e.g the space between the button and the picture
<StackPanel Orientation="Horizontal">
<Button Click="Button_Click" Padding="0" BorderThickness="0">
<Image Source="link-to-pic" Height="100"/>
</Button>
<Button Click="Button_Click" Padding="0" BorderThickness="0">
<Image Source="link-to-pic" Height="100"/>
</Button>
</StackPanel>

TabItem Header looks different as a Label

I have a TabItem and was previously setting the Header within the object like so,
<TabItem x:Name="Checked_Out_Items" Header="Clients In Use" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >
However, I've run into the problem where there is not a Click event for this Tab. I found a solution where we can insert a label as the header specified here,
how to handle TabItem single click event in WPF?
But, the Label looks nothing like what I need. Here is the Tab Header defined inside the object.
Here's what it looks like with the label
<TabItem x:Name="Checked_Out_Items" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >
<TabItem.Header>
<Label Content="Clients In Use" Height="40" MouseLeftButtonDown="Checked_Out_Items_Clicked" Width="171" />
</TabItem.Header>
Lets separate the concerns a bit.
In order to handle a mouse click event, a control needs to be prepared for receiving this event, it needs to implement a handler and the handler must actually receive the event. In case of TabItem the mouse click event is consumed by the control, without releasing the event to user defined listeners.
On the level of TabItem, the best option would be to handle the PreviewMouseLeftButtonDown event, but this is not an option if event handling shouldn't occur when child controls have their own handling functionality.
So the other option is to handle the MouseLeftButtonDown event before it reaches the TabItem, which means to handle it in a child control of the tab item.
As said, in order to receive the event, the control needs to be ready to receive the event. This means, it needs a Background not null (can be Transparent) and IsHitTestEnabled="True" (which is default in most cases) and it must actually handle the event.
For the showcase, I use a Red instead of Transparent background color. The red area is the place where mouse clicks are captured and handled.
<TabItem Padding="0">
<TabItem.Header>
<Border Height="30" Width="50"
Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
<ContentPresenter
VerticalAlignment="Center" HorizontalAlignment="Center"
Content="T2"/>
</Border>
</TabItem.Header>
Test Content 2
</TabItem>
Or, in order to have a better separation between header content and click handling, a HeaderTemplate can be used:
<TabItem Header="T3" Padding="0">
<TabItem.HeaderTemplate>
<DataTemplate>
<Border MinHeight="30" MinWidth="50"
Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
<ContentPresenter
VerticalAlignment="Center" HorizontalAlignment="Center"
Content="{Binding}"/>
</Border>
</DataTemplate>
</TabItem.HeaderTemplate>
Test Content 3
</TabItem>
The issue with any approach that relies on child controls is, that there is still a border of the TabItem and if the user clicks that border, the click will be outside of the child control and the tab will be selected without executing the click handler.
So a different way to handle tab changes (not clicks!) would be to handle the TabControl.SelectionChanged event and filter for events that actually originate from the TabControl and not from some inner content elements.
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source == sender)
{
// this selection change is actually issued because of a tab change
}
}
Another thing I just realized: The same condition could be used in TabItem.PreviewMouseLeftButtonDown in order to filter clicks to the tabitem header vs click events originating from the content area.
Edit:
The reason why Label is looking different is, that a font style is active for TabItem and Label is using some of its internal styles, ignoring the TabItem style.

How to expand a control beyond the parent's bounds?

I'm trying to popup a list box when a toggle button is clicked. In the code behind I work with the Visibility property and set it to Visibility.Visible. However, although the list box appears on the screen, it gets cropped to the size of the toggle box (30x30), instead of, as I wish it to, its own size (99x99).
<ToggleButton HorizontalAlignment="Left" Margin="0,0,0,0"
VerticalAlignment="Top" Width="30" Height="30"
Click="ButtonBase_OnClick">
<ListBox x:Name="listBox1"
ClipToBounds="False"
Visibility="Collapsed"
HorizontalAlignment="Left"
Height="99"
VerticalAlignment="Top"
Width="99">
<CheckBox x:Name="checkBox3" Content="CheckBox"/>
<CheckBox x:Name="checkBox4" Content="CheckBox"/>
</ListBox>
</ToggleButton>
I've tried setting the property ClipToBounds to false but it didn't give much change. I also tried setting the height of the combo box to Auto. That made a scroll bar appear (a horizontal one, though, which itself was a bit unexpected) but everything was still cropped to the toggle box's bounds.
What do I need to set more? Or am I approaching it the wrong way (as in: should I define the combo box inside the toggle button's child tags for templates, trigger and what not)?
If you don't want the listbox inside the toggle button, you should not place it inside the toggle button. Place it outside of the toggle button and it should work. Maybe you should have a look at the Expander control, that seems to do what you need. It will still not make the expanders body larger than the expander.
Something else to note: it's bad style to set fixed sizes. Try to partition your window using the containers like Grid and the various Panels and you will not need fixed sizes. If your toggle button does not have a fixed size, it could expand when the contents need expansion.

Problems with using Controls.Popup as error adorner in WPF

My (simplified) validation template is
<Grid>
<Border x:Name="ErrorAdorner"
BorderBrush="Red">
<AdornedElementPalceHolder />
</Border>
<Popup x:Name="ErrorPopup"
PalcementTarget="{Binding ElementName=ErrorAdorner}"
Placement="Bottom"
StaysOpen="false"
IsOpen="true">
<Grid>
<TextBloxk Text="Error!!!" />
</Grid>
</Popup>
</Grid>
The adorned element is typically a textbox
The problem I have with this approach is that, as soon as I click inside the textbox, the ErrorPopup disappears and the ErrorAdorner remains visible. Desired behavior is that both should stay visible.
Things tried:
Set StaysOpen to true on ErrorPopup. Problem: when you resize/move the parent window when the error is visible, the ErrorPopup remains at the same location, it doesnt move along with the textbox
Use a StackPanel around the textbox (adorned element) and the error message text block. Problem: Popup comes with positioning capabilities ie., if there is not enough screen area below the textbox for the adorner, it automatically relocates it. But if a stack panel is used, error message just cuts off if there is no space or it changes the textbox layout(not desired)
So in essence, I want to use the popup for its positional capabilities, but somehow want to fix the visibility problem
The problem here is that you can resize the window even if the cursor is inside the TextBox, you cannot get any useful state information out of that, so if you make the IsOpen dependent on that you still get dislocated popups.
Possibly this related question can help you with the placement.

Changing a property of something in XAML from a button click

Given the following bit of XAML
<Border Name="Brder" Visibility="Visible" Width="10" Height="10" Background="Red"></Border>
<Button Content="Hide"></Button>
How can I set the button click to change the visibility of the border (not using code behind)?
I know it's trivial in code behind and the routed click event only seems to allow storyboard manipulation?
Thanks
If you change the Button to a ToggleButton you can bind visibility to IsChecked of the ToggleButton using XAML only. Also remember that Expanders support this behavior as well and you can laways style them if you don't like the default look.

Resources