Как создать generic/re-usable модальное диалоговое окно для WPF после MVVM

Я хотел бы создать generic/re-usable модальное диалоговое окно, которое я могу использовать в нашем WPF (MVVM) - Приложение отделов организации WCF.

Я имею Представления и связал ViewModels, что я хотел бы отобразить диалоговые окна использования. Привязка между Представлениями и ViewModels сделана с помощью предназначенного Типа DataTemplates.

Вот некоторые требования, чтобы я смог спроектировать:

  • Я предпочитаю, чтобы это было основано на Окне вместо того, чтобы использовать Adorners и средства управления, которые действуют как модальное диалоговое окно.
  • Это должно получить свой минимальный размер от содержания.
  • Это должно центрироваться на окне владельца.
  • Окно не должно показывать Минимизирование и Кнопки развертывания окна.
  • Это должно получить свой заголовок от содержания.

Что лучший способ состоит в том, чтобы сделать это?

11
задан Andre Luus 2 June 2010 в 08:22
поделиться

2 ответа

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

Поехали.

Окно WPF, которое будет служить общим диалоговым окном, может выглядеть примерно так:

<Window x:Class="Example.ModalDialogView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ex="clr-namespace:Example"
        Title="{Binding Path=mDialogWindowTitle}" 
        ShowInTaskbar="False" 
        WindowStartupLocation="CenterOwner"
        WindowStyle="SingleBorderWindow"
        SizeToContent="WidthAndHeight"
        ex:WindowCustomizer.CanMaximize="False"
        ex:WindowCustomizer.CanMinimize="False"
        >
    <DockPanel Margin="3">
        <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" FlowDirection="RightToLeft">
            <Button Content="Cancel" IsCancel="True" Margin="3"/>
            <Button Content="OK" IsDefault="True" Margin="3" Click="Button_Click" />
        </StackPanel>
        <ContentPresenter Name="WindowContent" Content="{Binding}"/>
    </DockPanel>
</Window>

После MVVM правильный способ отображения диалогового окна - через посредника. Чтобы использовать посредник, вам также обычно требуется некоторый локатор служб. Подробную информацию о посредниках см. здесь .

Решение, на котором я остановился, включало реализацию интерфейса IDialogService, который разрешается с помощью простого статического ServiceLocator. В этой отличной статье о кодовом проекте есть подробности об этом. Обратите внимание на это сообщение на форуме статей. Это решение также решает проблему обнаружения окна владельца через экземпляр ViewModel.

Используя этот интерфейс, вы можете вызвать IDialogService.ShowDialog (ownerViewModel, dialogViewModel). На данный момент я вызываю это от ViewModel владельца, что означает, что у меня есть жесткие ссылки между моими ViewModel. Если вы используете агрегированные события, вы, вероятно, вызовете это из проводника.

Установка минимального размера в представлении, который в конечном итоге будет отображаться в диалоговом окне, не устанавливает автоматически минимальный размер диалогового окна. Кроме того, поскольку логическое дерево в диалоговом окне содержит ViewModel, вы не можете просто выполнить привязку к свойствам элемента WindowContent. На этот вопрос есть ответ с моим решением.

Ответ, который я упомянул выше, также включает код, который центрирует окно на владельце.

Наконец, отключение кнопок минимизации и развертывания - это то, чего WPF изначально не может сделать. ИМХО наиболее элегантное решение - использовать это .

7
ответ дан 3 December 2019 в 06:45
поделиться

Я обычно решаю эту проблему, вставляя этот интерфейс в соответствующие модели просмотра:

public interface IWindow
{
    void Close();

    IWindow CreateChild(object viewModel);

    void Show();

    bool? ShowDialog();
}

Это позволяет моделям просмотра создавать дочерние окна и показывать их модально в немодальных.

Многоразовая реализация IWindow такова:

public class WindowAdapter : IWindow
{
    private readonly Window wpfWindow;

    public WindowAdapter(Window wpfWindow)
    {
        if (wpfWindow == null)
        {
            throw new ArgumentNullException("window");
        }

        this.wpfWindow = wpfWindow;
    }

    #region IWindow Members

    public virtual void Close()
    {
        this.wpfWindow.Close();
    }

    public virtual IWindow CreateChild(object viewModel)
    {
        var cw = new ContentWindow();
        cw.Owner = this.wpfWindow;
        cw.DataContext = viewModel;
        WindowAdapter.ConfigureBehavior(cw);

        return new WindowAdapter(cw);
    }

    public virtual void Show()
    {
        this.wpfWindow.Show();
    }

    public virtual bool? ShowDialog()
    {
        return this.wpfWindow.ShowDialog();
    }

    #endregion

    protected Window WpfWindow
    {
        get { return this.wpfWindow; }
    }

    private static void ConfigureBehavior(ContentWindow cw)
    {
        cw.WindowStartupLocation = WindowStartupLocation.CenterOwner;
        cw.CommandBindings.Add(new CommandBinding(PresentationCommands.Accept, (sender, e) => cw.DialogResult = true));
    }
}

Вы можете использовать это окно как многоразовое хост-окно. Нет никакого кода программной части:

<Window x:Class="Ploeh.Samples.ProductManagement.WpfClient.ContentWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:self="clr-namespace:Ploeh.Samples.ProductManagement.WpfClient"
        xmlns:pm="clr-namespace:Ploeh.Samples.ProductManagement.PresentationLogic.Wpf;assembly=Ploeh.Samples.ProductManagement.PresentationLogic.Wpf"
        Title="{Binding Path=Title}"
        Height="300"
        Width="300"
        MinHeight="300"
        MinWidth="300" >
    <Window.Resources>
        <DataTemplate DataType="{x:Type pm:ProductEditorViewModel}">
            <self:ProductEditorControl />
        </DataTemplate>
    </Window.Resources>
    <ContentControl Content="{Binding}" />
</Window>

Вы можете узнать больше об этом (а также загрузить полный пример кода) в моей книге .

11
ответ дан 3 December 2019 в 06:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: