Как правильно получить вывод из диалога в WPF MVVM? - PullRequest
0 голосов
/ 04 ноября 2019

Я пытался найти ответы на свой вопрос в интернете, но ни один ответ меня не удовлетворил. Я пишу приложение WPF и пытаюсь реализовать механизм диалога. У меня есть простая ViewModel, и когда происходит какое-то событие, я хотел бы показать диалог, собрать из него некоторые выходные данные и сохранить их в «родительской» модели представления. Мой метод в модели представления выглядит следующим образом:

    private void Expand()
    {

        ...

        catch(ArgumentNullException)
        {

            Shrink();

            var errorDialogVM = new DialogVM(new Dialog() { Type = DialogType.Error, Message = $"Unauthorized access to \"{FileManager.GetDirectoryName(Path)}\" directory!" });

            DialogService.ShowDialog(errorDialogVM);

            //Here i need output from dialog

        }

    }

Реализация метода ShowDialog:

    public void ShowDialog(DialogVM dialogVM)
    {

        var dialog = new DialogBox();
        var mainWindow = Application.Current.MainWindow as MainWindow;

        dialog.DataContext = dialogVM;

        dialog.Owner = mainWindow;

        dialog.Show();

    }

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

Ответы [ 2 ]

0 голосов
/ 04 ноября 2019

Модель представления не должна обрабатывать элементы вида. Диалог является элементом представления.
Модель представления может инициировать ввод данных пользователем, вызывая событие, например, событие ошибки с моделью данных в качестве аргументов события. Представление, зарегистрированное для события, показывает диалоговое окно для сбора ввода пользователя и сохранения его в ранее полученной модели данных. Затем представление выполняет команду модели представления для передачи обратно модели данных.

Вместо события вы также можете привязать представление к свойству модели представления, например, типа bool. При изменении свойства откройте диалоговое окно и верните результат, используя ICommand.

. Альтернативно, пусть модель представления предоставляет флаг, например, HasException и свойство ExceptionDialogModel, которое можно использовать для привязки пользовательского диалога илисформироваться. Затем создайте простой модальный диалог самостоятельно:

ExampleDialog

<Grid x:Name="ExampleDialog"
      Visibility="Visible"
      Panel.ZIndex="100"
      VerticalAlignment="Top">
  <Rectangle Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=ActualWidth}"
             Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=ActualHeight}"
             Fill="Gray"
             Opacity="0.7" />
  <Grid Width="400"
        Height="200">
    <Grid.RowDefinitions>
      <RowDefinition Height="*" />
      <RowDefinition Height="100" />
    </Grid.RowDefinitions>
    <Border Grid.RowSpan="2"
            Background="LightGray"
            BorderBrush="Black"
            BorderThickness="1">
      <Border.Effect>
        <DropShadowEffect BlurRadius="5"
                          Color="Black"
                          Opacity="0.6" />
      </Border.Effect>
    </Border>
    <TextBlock Grid.Row="0"
               TextWrapping="Wrap"
               Margin="30"
               Text="I am a modal dialog and my Visibility or Opacity property can be easily modified by a trigger or a nice animation" />
    <StackPanel Orientation="Horizontal"
                Grid.Row="1"
                HorizontalAlignment="Right"
                Height="50">
      <Button x:Name="OkButton"
              Content="Ok"
              Width="80" />
      <Button x:Name="CancelButton"
              Margin="30,0,30,0"
              Content="Cancel"
              Width="80" />
    </StackPanel>
  </Grid>
  <Grid.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
      <BeginStoryboard>
        <Storyboard>
          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExampleDialog"
                                         Storyboard.TargetProperty="Visibility"
                                         Duration="0">
            <DiscreteObjectKeyFrame Value="{x:Static Visibility.Hidden}" />
          </ObjectAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Grid.Triggers>
</Grid>

Вы можете поместить Grid в любом месте вашего Window и переключать Visibility. Он перекрывает родительский элемент Window и имеет модальное поведение.
Привязывает DataContext к ExceptionDialogModel, чтобы данные отправлялись обратно через привязку TwoWay. Используйте команду для запуска процедуры повтора (например, кнопку OK или Retry ).
Visibility может связываться со свойством HasException. Вы можете оживить этот диалог и придать ему любой вид и чувствовать, что вам нравится.

0 голосов
/ 04 ноября 2019

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

public class MyDialog : Dialog
{
    public MyDialog(DialogVM ViewModel) {
        this.InitializeComponent();
        this.DataContex = ViewModel;
        // TODO: Bind to view model's properties in XAML or set them on OnClose()
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...