1

I am trying to solve what looks like a simple problem, but I can’t find a simple solution. I have a window in wpf, that window contains only of one listbox with few names and one button, the button don’t do anything. When you click on an item in the listbox it creates and shows a new window (child window). At this point I want the window behind to be disabled, but I also want the look of it not to change. However the listbox and the button (or any other control I put on that window) change their colour. How do I achieve the above, in the simplest possible way?

Here is the code:

<Window x:Class="MainWindowStyleAndBehaviour.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" WindowState="Maximized" Name="myWindow">
<Grid Background="Green">
    <ListBox Name="myListbox" HorizontalAlignment="Left" VerticalAlignment="Top" Height="200"     Width="300" Background="Red" FontSize="30" SelectionChanged="myListbox_SelectionChanged" Margin="10"/>
    <Button Content="Don't click me" Width="300" Height="60" HorizontalAlignment="Right" VerticalAlignment="Top" FontSize="30" Margin="10"/>
</Grid>
</Window>

 namespace MainWindowStyleAndBehaviour
 {
   public partial class MainWindow : Window
   {
     public MainWindow()
     {
        InitializeComponent();
        Names = new List<string>() { "Sonia", "Bruno", "Cezar" };
        myListbox.ItemsSource = Names;
     }

     public List<string> Names { get; set; }

     private void myListbox_SelectionChanged(object sender, SelectionChangedEventArgs e)
     {
        Window w = new Window();
        myWindow.IsEnabled = false;
        w.Show();
        w.Closed += (s, ea) => myWindow.IsEnabled = true;
     }
  }
}

Thank you in advance :)

adminSoftDK
  • 2,012
  • 1
  • 21
  • 41
  • Add a simple style for all the control and apply that style in both enabling and disenabling. – Ashok Rathod Sep 17 '14 at 10:43
  • Thanks, see my comment below. – adminSoftDK Sep 17 '14 at 12:35
  • Is there some reason why you don't use ShowDialog? – Dean Sep 17 '14 at 15:58
  • Yes there is, Im using Prism, and I have a few regions, I only need to disable the parent that opened the child, not the entire window behind. In other words only one region should be disabled. hopefully that makes sense. The dialog would not allow to go back to the MainWindow at all. – adminSoftDK Sep 17 '14 at 16:08
  • I added a sample project that does what I think you need. Please see the post below. – Dean Sep 17 '14 at 20:31

2 Answers2

2

You can overlay a grid control over the main window, and make it collapsed to start with. When you open the popup window (called OtherWindow below) make this grid Visible. Because it is on top of all other controls, it will capture all the mouse events, effectively disabling the whole window without changing its appearance.

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Input;

namespace Test
{
  public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();
    }

    private void listbox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
      utilityGrid.Visibility = System.Windows.Visibility.Visible;    // <- Crux
      OtherWindow otherWindow = new OtherWindow(ReturnToEnabled);
      PreviewKeyDown += MainWindow_PreviewKeyDown;
      otherWindow.Show();
    }

    private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
    {
      e.Handled = true;
    }

    private void ReturnToEnabled()
    {
      utilityGrid.Visibility = System.Windows.Visibility.Collapsed;
      PreviewKeyDown -= MainWindow_PreviewKeyDown;
    }
  }
}

MainWindow.xaml

<Window x:Class="Test.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">
    <Grid  >
      <Grid x:Name="PutYourStuffInHere">
      <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <ListBox Grid.Row="0" MouseDoubleClick="listbox_MouseDoubleClick" >
        <ListBoxItem>Double-Click</ListBoxItem>
        <ListBoxItem>Sample</ListBoxItem>
        <ListBoxItem>Text</ListBoxItem>
      </ListBox>
    </Grid>
    <Grid x:Name="utilityGrid" Background="White" Opacity="0.0" Visibility="Collapsed"></Grid>
  </Grid>
</Window>

OtherWindow.xaml.cs

using System;
using System.Windows;

namespace Test
{
  public partial class OtherWindow : Window
  {
    Action _returnToEnabled;
    public OtherWindow(Action ReturnToEnabled)
    {
      InitializeComponent();
      _returnToEnabled = ReturnToEnabled;
    }

    private void buttonClose_Click(object sender, RoutedEventArgs e)
    {
      Close();
    }

    private void OtherWindow_Closed(object sender, EventArgs e)
    {
      if (_returnToEnabled != null)
        _returnToEnabled();
    }
  }
}

OtherWindow.xaml

<Window x:Class="Test.OtherWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="OtherWindow" Height="300" Width="300" WindowStyle="ToolWindow"
        Closed="OtherWindow_Closed">
    <Grid>
    <Button Width="100" Height="25" x:Name="buttonClose" Click="buttonClose_Click">Close</Button>
    </Grid>
</Window>
Dean
  • 731
  • 8
  • 21
  • Let me add here that you can change the background and opacity of the 'utilityGrid' control above to give some indication to the user that something is disabled. Maybe a tinge, or slightly dulled appearance would be clearer to the end user. – Dean Sep 17 '14 at 20:33
  • Thank you very much for the project :). I tested it and it works great, it captures all the mouse events, but it still works with the Keyboard. So I can tab over controls in the MainWindow, use a hot key Shift+c, or simply use the arrows up and down, to navigate inside the listbox. Please see the code which I added to your MainWindow. I did not know how to put the code here, so I added it to your answer. Any ideas how to get arround that? Kind regards – adminSoftDK Sep 18 '14 at 08:31
  • 1
    @adminSoftDK I got a message from SO rejecting your edit - I think you will need to post it in its own message. Anyhow, you will have to make the covering grid intercept all keyboard events. I'll wait to see your code. – Dean Sep 18 '14 at 11:09
  • @adminSoftDK I added a few lines of code to the MainWindow.xaml.cs code to intercept the keyboard events. This stops keyboard interaction. – Dean Sep 18 '14 at 13:12
  • Thank you very much this solves the problem with keyboard. There is no need any more to post the code, I wanted to post, because that addition does the job :) – adminSoftDK Sep 18 '14 at 13:50
0

Your requirement is not trivial and will require you to work to achieve it. The default ControlTemplates for each control specify that they should have a distinct look when they are disabled. In order to remove that, you'll have to provide new ControlTemplates for all of the controls that are relevant for you.

You can do that by starting with the default ControlTemplates for each control and removing the relevant code that handles the IsEnabled property, or the Disabled VisualState element. You can find most of the default ControlTemplates for each control in the Control Styles and Templates page on MSDN.

For example, this comes from the default ControlTemplate for the Button from the linked page:

<VisualState x:Name="Disabled">
    <Storyboard>
      <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).
          (GradientBrush.GradientStops)[1].(GradientStop.Color)"
                                    Storyboard.TargetName="Border">
        <EasingColorKeyFrame KeyTime="0"
                             Value="{StaticResource DisabledControlDarkColor}" />
      </ColorAnimationUsingKeyFrames>
      <ColorAnimationUsingKeyFrames
          Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
                                    Storyboard.TargetName="Border">
        <EasingColorKeyFrame KeyTime="0"
                             Value="{StaticResource DisabledForegroundColor}" />
      </ColorAnimationUsingKeyFrames>
      <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush).
          (GradientBrush.GradientStops)[1].(GradientStop.Color)"
                                    Storyboard.TargetName="Border">
        <EasingColorKeyFrame KeyTime="0"
                             Value="{StaticResource DisabledBorderDarkColor}" />
      </ColorAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>

You could either replace this with your own colours, or simply remove it, so that when the control's IsEnabled property is true, there will be no change in its look.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Thank you I have tried something very similar, however there will be times when I need the controls to be in a disabled state. What I am after is making the control look enabled but it’s actually inactive, for example user cannot click on a button, cannot type into a textbox etc. – adminSoftDK Sep 17 '14 at 12:34
  • I know what you want because I read your question. I told you how to do what you want, so I don't really understand your comment. – Sheridan Sep 17 '14 at 12:49
  • I do not see a style change helping because when I popup a 'child' window over a 'parent' window I need to make the controls that are on the 'parent' window inactive, so a button still looks clickable but is not, a text box still looks like it can accept input but it cannot. Then I will need the option to disable a control on my 'child' window and therefore make it actually look disabled. I hope this helps. – adminSoftDK Sep 17 '14 at 13:47
  • Didn't I just tell you that I knew what you wanted? *I want the window behind to be disabled*... so set `IsEnabled` to `false`. *I also want the look of it not to change*... so define some `Style`s that DO NOT change the look of the controls that are disabled. *I am trying to solve what looks like a simple problem*... it *is* a simple problem. – Sheridan Sep 17 '14 at 13:51
  • @Dean, I'm guessing that you're asking the question author and not me and also that you meant `ShowDialog` and not `ShowModal`. It's a good point, but please comment on the *question* to speak with the question author... commenting on answers is generally for the answer authors. – Sheridan Sep 17 '14 at 15:36
  • @Sheridan Thanks - I moved the comment. And yes, I meant ShowDialog! – Dean Sep 17 '14 at 15:59
  • @Sheridan thank you for your time, I decided to use the solution provided in the accepted answer, because its just simpler for me. – adminSoftDK Sep 18 '14 at 13:53