adminSoftDK
adminSoftDK

Reputation: 2092

Disable the parent window, without changing the visual appearance of any of the controls

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 :)

Upvotes: 1

Views: 3514

Answers (2)

Dean
Dean

Reputation: 751

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>

Upvotes: 2

Sheridan
Sheridan

Reputation: 69959

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.

Upvotes: 0

Related Questions