none
MVVM - zusätzliches Eingabefenster erzeugen RRS feed

  • Frage

  • Hallo an Alle,

    ich habe eine ViewModel Klasse in der ich verschiedene Prüflinge aufliste. Nach jedem Wechsel der Prüflingszeile wird das View aktualisiert:

    // Ereignis, wenn neue Prüflingszeile im View angewählt wird cvsP.View.CurrentChanged += (object sender, EventArgs e) => { Pruefling = cvsP.View.CurrentItem as Pruefling; OnPropertyChanged("Pruefling"); if (Pruefling != null) { // Messpunkt Zaehler auf 0 setzen zaehlerMP = 0; // LiveModus Starten //mwTimer.Start(); try { MesspunktStatus = "Messpunkt: ...

    ... } };

    In dieser Routine möchte ich nun ein neues Eingabefenster erzeugen lasse. Indem der Anwender Zusatzdaten von Hand eingeben muss. Wie müsste man die Architektur vornehmen? Ist es erforderlich ein neues ViewModel zu erzeugen und wenn ja wie würde das aussehen?Ziel ist es ein Fenster zu erzeugen mit beispielsweise folgenden Eingaben:

    Mitarbeitername:           XY
    Arbeitsplatznummer:     01
    Uhrzeit:                         09:00

    Vielen Dank für eure HIlfe !!

    Donnerstag, 20. September 2018 06:38

Antworten

  • Hi,

    "UserInputDialogWindow" ist doch die Klasse des DialogWindows... Und die Klasse DialogService sorgt dafür, das durch instanzieren vom "UserInputDialogViewModel" das Window geöffnet wird.

    Warum sich bei dir nur ein weißes Window öffnet, kann ich nicht sagen. In meinem Beispiel habe ich doch ein paar Controls im UserInputDialogWindow erstellt. Wenn du das Window öffnest, solltest du mindestens diese sehen.

    Als Gegenfrage: wie möchtest du dein "EingabeFenster.xaml"- Window vom ViewModel aus öffnen, wenn man bedenkt, das irgendwelche Controls und/oder Frameworkelemente eigentlich nichts im VM zu suchen haben?

    Es gibt mit Sicherheit noch viele andere Möglichkeiten, wie man Dialoge handelt. Einige Frameworks bringen da auch schon etwas mit. Nutzt du ein solches (MVVMLight, Prism...)?

    Anstatt eines Windows, kannst du für einfache Eingaben auch ein PopUp erstellen. Das kannst du recht einfach vom ViewModel steuern und natürlich sämtliche Eigenschaften problemlos binden.

            <Popup Placement="Center" StaysOpen="False" IsOpen="{Binding IsPopupVisible}">
                <Border >
                    <StackPanel>
                        <TextBlock Text="Eingabe erforderlich:" FontSize="20" FontWeight="ExtraBold" HorizontalAlignment="Center"/>
                        <TextBlock Text="Mitarbeiter:"/>
                        <TextBox Text="{Binding Mitarbeitername}"/>
                        <TextBlock Text="Arbeitsplatznummer:"/>
                        <TextBox Text="{Binding Arbeitsplatznummer}"/>
                        <Button Content="Close Popup" Command="{Binding ClosePopupCommand}"/>
                    </StackPanel>
                </Border>
            </Popup>
            public ICommand OpenPopupCommand { get; internal set; }
            public ICommand ClosePopupCommand { get; internal set; }
    
            public Window69VM()
            {
                OpenPopupCommand = new RelayCommand(o => { OpenPopup(); }, o => true);
                ClosePopupCommand = new RelayCommand(o => { ClosePopup(); }, o => true);
            }
    
    ...
    ...
    ...
    
            private void OpenPopup()
            {
                IsPopupVisible = true;
            }
    
            private void ClosePopup()
            {
                IsPopupVisible = false;
            }
    
            private bool isPopupVisible;
            public bool IsPopupVisible
            {
                get { return isPopupVisible; }
                set
                {
                    if (isPopupVisible == value)
                        return;
                    isPopupVisible = value;
                    NotifyPropertyChange("IsPopupVisible");
                }
            }

    ...auf die schnelle getippt.

    Gruß


    Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP



    • Bearbeitet Stefan Krömer Donnerstag, 20. September 2018 13:08
    • Als Antwort markiert mApO18 Freitag, 21. September 2018 07:03
    Donnerstag, 20. September 2018 12:44

Alle Antworten

  • Hi, du könntest dir einen "DialogService" erstellen.

    Ich habe mal eine kleine Demo erstellt:

    Window, welches den Dialog öffnet:

    <Window x:Class="WpfApp4.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp4"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.Resources>
            <local:Window69VM x:Key="vm"/>
        </Window.Resources>
        <Grid DataContext="{StaticResource vm}">
            <StackPanel>
                <Button Content="Open Dialog" Command="{Binding OpenUserInputCommand}"/>
            </StackPanel>
        </Grid>
    </Window>

    Das ViewModel zu Window:

    using System.ComponentModel;
    using System.Windows.Input;
    
    namespace WpfApp4
    {
        public class Window69VM : INotifyPropertyChanged
        {
            public ICommand OpenUserInputCommand { get; internal set; }
    
            public Window69VM()
            {
                OpenUserInputCommand = new RelayCommand(o => { OpenUserInput(); }, o => true);
            }
    
            private void OpenUserInput()
            {
                UserInputDialogViewModel userInputDialogViewModel = new UserInputDialogViewModel();
                var result = DialogService.Instance.ShowDialog(userInputDialogViewModel);
    
                if (result.HasValue && result.Value)
                {
                    //accept true
                    var res = userInputDialogViewModel.Mitarbeitername;
                }
            }
            
            /// <summary>
            /// Occurs when a property value changes
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
    
            /// <summary>
            /// Raise the  <see cref="PropertyChanged"/> event.
            /// </summary>
            /// <param name="propertyName"></param>
            protected void NotifyPropertyChange(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    Das Dialog-Window:

    <Window x:Class="WpfApp4.UserInputDialogWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp4"
            mc:Ignorable="d"
            Title="UserInputDialogWindow" Height="150" Width="500">
        <Grid>
            <StackPanel>
                <TextBlock Text="Mitarbeiter:"/>
                <TextBox Text="{Binding Mitarbeitername}"/>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Button Content="OK" Click="ButtonOk_Click"/>
                    <Button Content="Cancle" Click="ButtonCancle_Click" Grid.Column="1"/>
                </Grid>
            </StackPanel>
        </Grid>
    </Window>

    Der Code-Behind dazu (für das Dialog-Result):

    using System.Windows;
    
    namespace WpfApp4
    {
        /// <summary>
        /// Interaktionslogik für UserInputDialogWindow.xaml
        /// </summary>
        public partial class UserInputDialogWindow : Window
        {
            public UserInputDialogWindow()
            {
                InitializeComponent();
            }
    
            private void ButtonOk_Click(object sender, RoutedEventArgs e)
            {
                this.DialogResult = true;
            }
    
            private void ButtonCancle_Click(object sender, RoutedEventArgs e)
            {
                this.DialogResult = false;
            }
        }
    }

    Und das ViewModel zum Dialog:

    using System.ComponentModel; namespace WpfApp4 { public class UserInputDialogViewModel : INotifyPropertyChanged {

    private string mitarbeitername = ""; public string Mitarbeitername { get { return mitarbeitername; } set { if (mitarbeitername != value) { mitarbeitername = value; NotifyPropertyChange("Mitarbeitername"); } } } /// <summary> /// Occurs when a property value changes /// </summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Raise the <see cref="PropertyChanged"/> event. /// </summary> /// <param name="propertyName"></param> protected void NotifyPropertyChange(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }


    Und zum Schluss noch der DialogService:

    namespace WpfApp4
    {
        class DialogService
        {
            private static volatile DialogService instance;
            private static object syncroot = new object();
    
            private DialogService() { }
    
            public bool? ShowDialog(UserInputDialogViewModel viewModel)
            {
                UserInputDialogWindow dialog = new UserInputDialogWindow() { DataContext = viewModel };
                dialog.ShowInTaskbar = false;
                return dialog.ShowDialog();
            }
    
            public static DialogService Instance
            {
                get
                {
                    if (instance == null)
                    {
                        lock (syncroot)
                        {
                            if (instance == null)
                            {
                                instance = new DialogService();
                            }
                        }
                    }
                    return instance;
                }
            }
        }
    }

    So kannst du (zum Beispiel) einen Dialog aus einem ViewModel aufrufen und bleibst dem MVVM- Entwurfsmuster treu.

    Gruß Stefan


    Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP





    Donnerstag, 20. September 2018 08:17
  • Hallo Stefan,

    vielen Dank für deine Antwort.

    Ich habe den Code soweit eingepflegt. Nun öffnet er allerdings ein weißes leeres Window, ohne Textinhalt. Es wird nur das Firmenlogo oben links in der Ecke angezeigt.

    Benötigt man die
    Klassen UserInputDialogWindow und DialogService unbedingt oder kann man auch nur mit der EingabeFenster.xaml und der dazugehörigen neuen ViewModel Klasse arbeiten und über Bindings arbeiten?

    Danke dir.

    Donnerstag, 20. September 2018 11:56
  • Hi,

    "UserInputDialogWindow" ist doch die Klasse des DialogWindows... Und die Klasse DialogService sorgt dafür, das durch instanzieren vom "UserInputDialogViewModel" das Window geöffnet wird.

    Warum sich bei dir nur ein weißes Window öffnet, kann ich nicht sagen. In meinem Beispiel habe ich doch ein paar Controls im UserInputDialogWindow erstellt. Wenn du das Window öffnest, solltest du mindestens diese sehen.

    Als Gegenfrage: wie möchtest du dein "EingabeFenster.xaml"- Window vom ViewModel aus öffnen, wenn man bedenkt, das irgendwelche Controls und/oder Frameworkelemente eigentlich nichts im VM zu suchen haben?

    Es gibt mit Sicherheit noch viele andere Möglichkeiten, wie man Dialoge handelt. Einige Frameworks bringen da auch schon etwas mit. Nutzt du ein solches (MVVMLight, Prism...)?

    Anstatt eines Windows, kannst du für einfache Eingaben auch ein PopUp erstellen. Das kannst du recht einfach vom ViewModel steuern und natürlich sämtliche Eigenschaften problemlos binden.

            <Popup Placement="Center" StaysOpen="False" IsOpen="{Binding IsPopupVisible}">
                <Border >
                    <StackPanel>
                        <TextBlock Text="Eingabe erforderlich:" FontSize="20" FontWeight="ExtraBold" HorizontalAlignment="Center"/>
                        <TextBlock Text="Mitarbeiter:"/>
                        <TextBox Text="{Binding Mitarbeitername}"/>
                        <TextBlock Text="Arbeitsplatznummer:"/>
                        <TextBox Text="{Binding Arbeitsplatznummer}"/>
                        <Button Content="Close Popup" Command="{Binding ClosePopupCommand}"/>
                    </StackPanel>
                </Border>
            </Popup>
            public ICommand OpenPopupCommand { get; internal set; }
            public ICommand ClosePopupCommand { get; internal set; }
    
            public Window69VM()
            {
                OpenPopupCommand = new RelayCommand(o => { OpenPopup(); }, o => true);
                ClosePopupCommand = new RelayCommand(o => { ClosePopup(); }, o => true);
            }
    
    ...
    ...
    ...
    
            private void OpenPopup()
            {
                IsPopupVisible = true;
            }
    
            private void ClosePopup()
            {
                IsPopupVisible = false;
            }
    
            private bool isPopupVisible;
            public bool IsPopupVisible
            {
                get { return isPopupVisible; }
                set
                {
                    if (isPopupVisible == value)
                        return;
                    isPopupVisible = value;
                    NotifyPropertyChange("IsPopupVisible");
                }
            }

    ...auf die schnelle getippt.

    Gruß


    Freiberufler im Bereich Softwareentwicklung Von der PLC und Robotik zu VB.NET & C#, vorrangig WPF und UWP



    • Bearbeitet Stefan Krömer Donnerstag, 20. September 2018 13:08
    • Als Antwort markiert mApO18 Freitag, 21. September 2018 07:03
    Donnerstag, 20. September 2018 12:44
  • Danke dir.

    Ich nutz halt Visual Studio und bau dort mein MVVM auf. Ich bin aber noch ziemlich neu auf dem Gebiet. Aktuell habe ich in meinem ViewModel schon Buttons , etc. eingepflegt. Bis jetzt funktioniert es so ganz gut.

    Viele Grüße

    Martin


    • Bearbeitet mApO18 Freitag, 21. September 2018 07:06
    Freitag, 21. September 2018 07:04