none
Вложенные диалоги Grid WPF RRS feed

  • Вопрос

  • Здравствуйте!

    Есть главное окно программы, в окне есть Grid.

    Задача следующая: нужно во время работы программы все диалоги с пользователем(настройки программы и тд) показывать в этом Grid, скрывая всё что в нем было до этого.

    Вопрос:

    Как это правильно сделать? Т.е. например в разметке кода в Grid создать заранее все группы контролов для каждого окна и менять у них свойство Visible или динамически создавать контролы, привязывать к ним события и добавлять их в грид. Как лучше?

    Заранее благодарен

    16 июня 2013 г. 15:52

Ответы

  • Добрый день.

    Делали мы такую задачу... Все решение здесь приводить не буду, т.к. оно замороченное, это надо отдельную статью писать. А вот простой пример, пожалуйста.

    1. Создал новое WPF приложение.

    2. На главной форме сделал вот такой XAML:

    <Window x:Class="WpfApplication1.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 Background="LightGray">
            <Grid x:Name="grMain"> <!--Это Grid основного окна-->
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*" />
                    <RowDefinition Height="1*" />
                </Grid.RowDefinitions>
                <TextBlock Text="Привет!" />
                <Button x:Name="btShowWindow" Content="Нажми меня" Margin="0,20,0,0" Click="btShowWindow_Click" />
                <TextBox Grid.Row="1" Margin="5" />
            </Grid>
            <Grid x:Name="grWindow"> <!--Это Grid для показа всплывающих окон-->
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="1*" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="auto" />
                    <ColumnDefinition Width="1*" />
                </Grid.ColumnDefinitions>
            </Grid>
        </Grid>
    </Window>

    3. Добавил в проект новый UserControl вот с таким XAML:

    <UserControl x:Class="WpfApplication1.UserControl1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 Height="auto" Width="300">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
                <RowDefinition Height="auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
            </Grid.ColumnDefinitions>
            <TextBlock Grid.ColumnSpan="100" Text="Вы уверены?" Margin="5" />
            <Button x:Name="btApply" Content="Принять" Grid.Row="1" Grid.Column="1" Click="btApply_Click" />
            <Button x:Name="btCancel" Content="Отмена" Grid.Row="1" Grid.Column="2" Click="btCancel_Click" />
        </Grid>
    </UserControl>

    И вот таким кодом:

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        public event Action<bool> CloseRequered;
    
        protected void OnCloseRequered(bool p_param)
        {
            var handler = CloseRequered;
            if (handler != null)
            {
                handler(p_param);
            }
        }
    
        private void btApply_Click(object sender, RoutedEventArgs e)
        {
            OnCloseRequered(true);
        }
    
        private void btCancel_Click(object sender, RoutedEventArgs e)
        {
            OnCloseRequered(false);
        }
    }

    Событие необходимо, для уведомления родительского окна, о том, что это компонент надо закрывать.

    4. Ну и код главной формы:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void ShowModal()
        {
            UserControl1 uc = new UserControl1();
            uc.CloseRequered += new Action<bool>(uc_CloseRequered);
            grMain.Visibility = Visibility.Hidden;
            Grid.SetRow(uc, 1);
            Grid.SetColumn(uc, 1);
            grWindow.Children.Add(uc);
        }
    
        void uc_CloseRequered(bool param)
        {
            if (param)
            {
                MessageBox.Show("Ок");
            }
            else
            {
                MessageBox.Show("No");
            }
            while (grWindow.Children.Count > 0)
            {
                grWindow.Children.RemoveAt(0);
            }
            grMain.Visibility = Visibility.Visible;
        }
    
        private void btShowWindow_Click(object sender, RoutedEventArgs e)
        {
            ShowModal();
        }
    }

    Запускаем:

    Кликаем на кнопке:

    Ну и если кликнуть на принять или отмена, увидим соответствующий MessageBox и после его закрытия первоначальную форму.

    P.s. Если эту штуку делать универсальной, то я бы наследовал контроля от интерфейса с событием CloseRequered, а метод ShowModal принимал бы этот интерфейс и метод, который надо вызвать при закрытии окна.

    16 июня 2013 г. 18:16
    Отвечающий

Все ответы

  • Лучше делать конечно в отдельных окнах, но если задача такая, то вы можете заранее в XAML прописать все панели с нужными элементами а их Visible через конвертер привязать к некому свойству, которое будет отвечать за то какая сейчас панель отображается. Все далее в месте где происходит переключение панелей просто меняете значение свойства, а все привязки обновляют свой Visible и показывается нужная панель.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    16 июня 2013 г. 17:05
    Отвечающий
  • Добрый день.

    Делали мы такую задачу... Все решение здесь приводить не буду, т.к. оно замороченное, это надо отдельную статью писать. А вот простой пример, пожалуйста.

    1. Создал новое WPF приложение.

    2. На главной форме сделал вот такой XAML:

    <Window x:Class="WpfApplication1.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 Background="LightGray">
            <Grid x:Name="grMain"> <!--Это Grid основного окна-->
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*" />
                    <RowDefinition Height="1*" />
                </Grid.RowDefinitions>
                <TextBlock Text="Привет!" />
                <Button x:Name="btShowWindow" Content="Нажми меня" Margin="0,20,0,0" Click="btShowWindow_Click" />
                <TextBox Grid.Row="1" Margin="5" />
            </Grid>
            <Grid x:Name="grWindow"> <!--Это Grid для показа всплывающих окон-->
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="1*" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="auto" />
                    <ColumnDefinition Width="1*" />
                </Grid.ColumnDefinitions>
            </Grid>
        </Grid>
    </Window>

    3. Добавил в проект новый UserControl вот с таким XAML:

    <UserControl x:Class="WpfApplication1.UserControl1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 Height="auto" Width="300">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
                <RowDefinition Height="auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
            </Grid.ColumnDefinitions>
            <TextBlock Grid.ColumnSpan="100" Text="Вы уверены?" Margin="5" />
            <Button x:Name="btApply" Content="Принять" Grid.Row="1" Grid.Column="1" Click="btApply_Click" />
            <Button x:Name="btCancel" Content="Отмена" Grid.Row="1" Grid.Column="2" Click="btCancel_Click" />
        </Grid>
    </UserControl>

    И вот таким кодом:

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        public event Action<bool> CloseRequered;
    
        protected void OnCloseRequered(bool p_param)
        {
            var handler = CloseRequered;
            if (handler != null)
            {
                handler(p_param);
            }
        }
    
        private void btApply_Click(object sender, RoutedEventArgs e)
        {
            OnCloseRequered(true);
        }
    
        private void btCancel_Click(object sender, RoutedEventArgs e)
        {
            OnCloseRequered(false);
        }
    }

    Событие необходимо, для уведомления родительского окна, о том, что это компонент надо закрывать.

    4. Ну и код главной формы:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void ShowModal()
        {
            UserControl1 uc = new UserControl1();
            uc.CloseRequered += new Action<bool>(uc_CloseRequered);
            grMain.Visibility = Visibility.Hidden;
            Grid.SetRow(uc, 1);
            Grid.SetColumn(uc, 1);
            grWindow.Children.Add(uc);
        }
    
        void uc_CloseRequered(bool param)
        {
            if (param)
            {
                MessageBox.Show("Ок");
            }
            else
            {
                MessageBox.Show("No");
            }
            while (grWindow.Children.Count > 0)
            {
                grWindow.Children.RemoveAt(0);
            }
            grMain.Visibility = Visibility.Visible;
        }
    
        private void btShowWindow_Click(object sender, RoutedEventArgs e)
        {
            ShowModal();
        }
    }

    Запускаем:

    Кликаем на кнопке:

    Ну и если кликнуть на принять или отмена, увидим соответствующий MessageBox и после его закрытия первоначальную форму.

    P.s. Если эту штуку делать универсальной, то я бы наследовал контроля от интерфейса с событием CloseRequered, а метод ShowModal принимал бы этот интерфейс и метод, который надо вызвать при закрытии окна.

    16 июня 2013 г. 18:16
    Отвечающий