Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von Caveman
Thema: Code auslagern (in Klassen?) - Verbindung zur MainWindow klappt nicht (VB.NET Umsteiger)
Am Gestern, im Forum: GUI: WPF und XAML

In WPF könnte dies so aussehen:
Pakete CommunityToolkit.Mvvm installieren für das RelayCommand.
Microsoft.Xaml.Behaviors.Wpf installieren für die Eventverarbeitung

Ein MainWindow erstellen, ViewModel (vm) und Behaviors (behav) definieren.
Datenbindung für das Window loaded event und den Text für das Label erstellen.


<Window x:Class="MyCSharp125145.Views.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:behav="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:vm="clr-namespace:MyCSharp125145.ViewModels"
        mc:Ignorable="d"
        Title="MainWindow" 
        Height="150" 
        Width="250">

    <Window.DataContext>
        <vm:MainWindowViewModel />
    </Window.DataContext>
    
    <behav:Interaction.Triggers>
        <behav:EventTrigger EventName="Loaded">
            <behav:InvokeCommandAction Command="{Binding WindowLoadedEventCommand}" />
        </behav:EventTrigger>
    </behav:Interaction.Triggers>

    
    <Grid>
        <Label x:Name="welcomeLabel"
               Content="{Binding WelcomeLabelText}" />
    </Grid>
</Window>

Wir brauchen auch ein ViewModel, das die Logik des MainWindows enthält. Dieses ist abgeleitet von ViewModelBase


public class MainWindowViewModel : ViewModelBase
    {
		private string welcomeLabelText;

		public string WelcomeLabelText
        {
			get { return welcomeLabelText; }
			set
			{
				if (welcomeLabelText != value)
				{
                    welcomeLabelText = value;
					OnPropertyChanged();
				}
			}
		}

		public ICommand WindowLoadedEventCommand { get; private set; }

		public MainWindowViewModel()
		{
			WindowLoadedEventCommand = new RelayCommand(SetLabelText);
		}

		private void SetLabelText()
		{
            WelcomeLabelText = "Hallo";
        }
	}

    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Thema: Inhalt der Combobox wird trotz Data-Binding nicht aktualisiert
Am im Forum: GUI: WPF und XAML

Also ich weiß jetzt nicht genau, ob ich das Problem verstanden habe.
Aber wenn im UserControl folgendes steht


<vm IrgendeineViewModelKlasse x:Key="Schluessel"/>
,
dann wird doch für jedes Usercontrol eine eigene Instanz erstellt. Das ist dann nicht das gleiche.

Eine ObservableCollection braucht im Übrigen auch kein PropertyChanged, weil dies bereits in der ObservableCollection implementiert ist.

Folgendes sollte funktionieren.


    public class IrgendeineViewModelKlasse : INotifyPropertyChanged
    {
        public ObservableCollection<IrgendeineKlasseAusDB> Sammlung { get; set; }

        public IrgendeineViewModelKlasse()
        {
            Sammlung = new ObservableCollection<IrgendeineKlasseAusDB>();
        }

        private string neueStation;

        public string NeueStation
        {
            get { return neueStation; }
            set
            {
                if (neueStation != value)
                {
                    neueStation = value;
                    OnPropertyChanged(nameof(NeueStation));
                    if (neueStation.EndsWith('#'))
                    {
                        AddNeueStation();
                    }
                }
            }
        }

        private void AddNeueStation()
        {
            Sammlung.Add(new IrgendeineKlasseAusDB() { Ortsname = NeueStation.TrimEnd('#') });
            NeueStation = string.Empty;
        }

        public event PropertyChangedEventHandler? PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class IrgendeineKlasseAusDB
    {
        public string Ortsname { get; set; }
    }


<UserControl x:Class="MyCSharp125121.StationView"
             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">
    
    <Grid>
        <ComboBox ItemsSource="{Binding Sammlung}"
                  DisplayMemberPath="Ortsname" />
    </Grid>
</UserControl>


<Window x:Class="MyCSharp125121.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:MyCSharp125121"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    
    <Window.DataContext>
        <local:IrgendeineViewModelKlasse />
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Grid Grid.Column="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <local:StationView x:Name="Stationen" 
                               Grid.Column="0"
                               Grid.ColumnSpan="2"
                               Grid.Row="0" />
            <TextBox Grid.Row="1"
                     Grid.Column="0"
                     Grid.ColumnSpan="2"
                     Text="{Binding NeueStation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </Grid>
        <local:StationView x:Name="Strecken" Grid.Column="1" />
    </Grid>
</Window>

Ich weiß, dass ich damit keinen Schönheitspreis gewinnen kann!

Thema: Anwendung über C#-exe starten funktioniert, über Verknüpfing nicht
Am im Forum: Grundlagen von C#

Zitat von LittleTester
Ich nutze doch nur eine Abkürzung um die exe aus zu führen und trotzdem ist ein Workingdir notwendig? Was passiert da im Hintergrund?

Die Antwort hast Du Dir doch im Eingangspost schon selber gegeben! Deine Exe findet doch auch die Dateien nicht selber, wenn sie in einem anderen Ordner als die CMD-Dateien liegt.
Vereinfacht gesagt, ist der Arbeitsordner immer der Ordner, in dem das Programm gestartet wird, wenn nichts anderes angegeben wird. In Deinem Fall mit der Verknüpfung wird das Programm halt dann wahrscheinlich vom Desktop getsartet und der Arbeitsordner ist eben der Desktop.

Thema: ListBox mit 'ObservableCollection' über DataContext füllen
Am im Forum: GUI: WPF und XAML

Erstelle ein ViewModel


public class MainWindowViewModel
    {
        public ObservableCollection<Auto> AutoListe { get; set; }

        public MainWindowViewModel()
        {
            AutoListe = new ObservableCollection<Auto>()
            {
                new Auto() { Marke = "Audi", Modell = "R8", PS = 610, Logo = "Images/logo_audi.jpg" },
                new Auto() { Marke = "Bentley", Modell = "CS", PS = 630, Logo = "Images/logo_bentley.jpg" },
                new Auto() { Marke = "Lambo", Modell = "LP 700", PS = 700, Logo = "Images/logo_lambo.jpg" },
                new Auto() { Marke = "SEAT", Modell = "DSG", PS = 300, Logo = "Images/logo_seat.jpg" },
                new Auto() { Marke = "Skoda", Modell = "RS", PS = 230, Logo = "Images/logo_skoda.jpg" },
                new Auto() { Marke = "VW", Modell = "TDI 8", PS = 240, Logo = "Images/logo_vw.jpg" }
            };
        }
    }

Erstelle eine Instanz des Viemodels in der View und definiere die Listbox. Das Datatemplate muss nach den Bedürfnissen angepasst werden.

<Window x:Class="MyCSharp125114.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:MyCSharp125114"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    
    <Grid>
        <ListBox Name="MyListBox"  Margin="10" ItemsSource="{Binding AutoListe}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Logo}" />
                        <TextBlock Margin="10, 0" Text="{Binding Marke}" />
                        <TextBlock Text="{Binding Modell}" />
                        <TextBlock Margin="10, 0" Text="{Binding PS}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Thema: fehler Unerreichbar code wurde entdeckt
Am im Forum: Web-Technologien

Das break in der for-Schleife sorgt dafür, dass die Schleife bereits beim ersten Durchlauf verlassen wird.

Thema: Visual Studio Editor Comboboxen Konfiguration
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Servus,

lassen sich eigentlich die Beiden ComboBoxen (Prjektmappenkonfiguration und Projektmappenplattform) in Visual Studio in der Breite anpassen?

Thema: Probleme beim Lösen einer Hausaufgabe zum Umgang mit StreamWriter
Am im Forum: Grundlagen von C#

Geht doch! Da fehlt nur eine Klammer und statt einem Komma braucht man ein Semikolon.


try
{
    using (wr = new StreamWriter(dateiname))
        for (int zl = 0; zl < breite; ++zl)
        {
            for (int sp = 0; sp < breite; ++sp)
            {
                int dist = breite - zl;
                //if ((zl - sp) % 5 == 0)
                //{
                //    wr.Write('+');
                //}
                //else
                //{
                //    wr.Write('_');
                //}
                wr.Write((zl - sp) % 5 == 0 ? '+' : '_');
            }
            wr.WriteLine();
        }
}

Thema: Webseiten Link automatisch abfragen
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Also ich würde es wahrscheinlich mit einer Regenechse machen.
Es wird sich ja wahrscheinlich nur der Teil nach dem ? ändern.

Thema: Richtiges Binden von selektierten Listen an ein ListItem
Am im Forum: GUI: WPF und XAML

Ich mache das mit dem Nuget-Paket Microsoft.Xaml.Behaviors.Wpf.


<Window x:Class="CSharp124655.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:CSharp124655"
        xmlns:behav="http://schemas.microsoft.com/xaml/behaviors"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>
        <DataTemplate x:Key="AddressTemplate" DataType="{x:Type local:AddressViewModel}">
            <Border BorderThickness="2"
                    BorderBrush="Black"
                    CornerRadius="3"
                    Padding="3">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="10" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Row="0"
                           Grid.Column="0">
                    <Run Text="ID: " />
                    <Run Text="{Binding Id}" />
                </TextBlock>
                <TextBlock Grid.Row="1"
                           Grid.Column="0">
                    <Run Text="StockName: " />
                    <Run Text="{Binding StockName}" />
                </TextBlock>
                <TextBlock Grid.Row="2"
                           Grid.Column="0">
                    <Run Text="City: " />
                    <Run Text="{Binding City}" />
                </TextBlock>
                <TextBlock Grid.Row="0"
                           Grid.Column="2">
                    <Run Text="Postal code: " />
                    <Run Text="{Binding Postcode}" />
                </TextBlock>
                <TextBlock Grid.Row="1"
                           Grid.Column="2">
                    <Run Text="Street: " />
                    <Run Text="{Binding Street}" />
                </TextBlock>
                <TextBlock Grid.Row="2"
                           Grid.Column="2">
                    <Run Text="HouseNumber: " />
                    <Run Text="{Binding HouseNumber}" />
                </TextBlock>
            </Grid>
            </Border>
        </DataTemplate>
    </Window.Resources>

    <Window.DataContext>
        <local:MainWindowViewModel x:Name="DataContext" />
    </Window.DataContext>
    
    <Grid>
        <ListBox x:Name="AddressesListBox"
                 ItemsSource="{Binding Addresses}"
                 SelectedItem="{Binding SelectedAddress}"
                 SelectionMode="Single" 
                 ItemTemplate="{StaticResource AddressTemplate}">
            <behav:Interaction.Triggers>
                <behav:EventTrigger EventName="SelectionChanged">
                    <behav:InvokeCommandAction Command="{Binding OnSelectionChanged}" />
                </behav:EventTrigger>
            </behav:Interaction.Triggers>
        </ListBox>

    </Grid>
</Window>


using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;

namespace CSharp124655
{
    public class MainWindowViewModel : ViewModelBase
    {
        public ObservableCollection<AddressViewModel> Addresses { get; private set; }

        public AddressViewModel SelectedAddress { get; set; }

        public ICommand OnSelectionChanged { get; private set; }

        public MainWindowViewModel()
        {
            Addresses = new ObservableCollection<AddressViewModel>();
            for (int i = 1; i < 6; i++)
            {
                Addresses.Add(new AddressViewModel() { City = $"City{i}", HouseNumber = i, Id = i + 10000, Postcode = $"12340{i}", StockName = $"Name{i}", Street = $"Street{i}" });
            }

            OnSelectionChanged = new RelayCommand(o => { ContinueWithSelectedItem(); });
        }

        private void ContinueWithSelectedItem()
        {
            Debug.WriteLine(SelectedAddress.StockName);
        }
    }
}

Thema: FolderBrowserDialog() Com Verweis hinzufügen
Am im Forum: GUI: WPF und XAML

Falls Dein Projekt .Net5/6 ist, dann einfach in der Projektdatei (.csproj) WindowsForms aktivieren.


<UseWindowsForms>true</UseWindowsForms>

Danach kannst Du den FolderBrowserDialog aufrufen.


System.Windows.Forms.FolderBrowserDialog folderBrowsingDialog = new System.Windows.Forms.FolderBrowserDialog

Es ist eigentlich kein Gefrickel mit COM notwendig!

Thema: Diskussion: Subscriptions vs. Einzelplatzlizenzen
Am im Forum: Smalltalk

You will own nothing and you will be happy!

Thema: c# JSON Api für Personio
Am im Forum: Web-Technologien

Zitat von ChrisBa
Kann mir bitte jemand helfen?

Ich bekomme den Fehler: "The JSON value could not be converted to System.String. Path: $.success | LineNumber: 0 | BytePositionInLine: 15."
Bei diesem Code:


public class Mitarbeiter
    {
        public string success { get; set; }
        public Data data { get; set; }
    }

Ändere die Mitarbeiterklasse wie folgt:


public class Mitarbeiter
    {
        public bool success { get; set; }
        public Data data { get; set; }
    }

Thema: Bild kann nicht gelöscht werden, während es angezeigt wird
Am im Forum: GUI: WPF und XAML

Zitat von Abt
@Caveman das sieht nach .NET 3.5 Code oder früher aus.
Seit .NET 4 kann man einfach CopyTo verwenden

Ich habe in dem Fall einfach nur stur gegoogelt und die erstbesten Beispiele von StackOverflow kopiert.
Dass mit CopyTo habe ich gelesen, wollte es aber nicht posten, weil es dann keine 5 Zeilen Code geworden wären

Deswegen hatte ich auch geschrieben, dass ich das selber nicht probiert hatte.

Thema: Bild kann nicht gelöscht werden, während es angezeigt wird
Am im Forum: GUI: WPF und XAML

Ein Bild in den Speicher laden


using (MemoryStream ms = new MemoryStream())
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
   byte[] bytes = new byte[file.Length];
   file.Read(bytes, 0, (int)file.Length);
   ms.Write(bytes, 0, (int)file.Length);
}

Im View Model eine Eigenschaft vom Typ byte[] anlegen


private byte[] userImage;

public byte[] UserImage
   {
       get { return userImage; }
       set
       {
           if (value != userImage)
           {
               userImage = value;
               OnPropertyChanged("UserImage");
           }
       }
   }

Und im Xaml darauf binden

<Image Source="{Binding UserImage}"/>

Alles ungetestet! Das Byte-Array muss noch mit der Eigenschaft UserImage verbunden werden.

Thema: Wert aus Viewmodel an ein anderes Model/Viewmodel übergeben
Am im Forum: GUI: WPF und XAML

Ich habe auf Github eine zweite Version veröffentlicht.

In dieser Version wird ein "Navigator" zum Umschalten der ViewModels verwendet.

MainView:


<Window x:Class="Forum124378II.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:Forum124378II"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="300">

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:CustomerViewModel}">
            <local:Customers />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:DealerViewModel}">
            <local:Dealers />
        </DataTemplate>
    </Window.Resources>
    
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="60" />
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0"
                    Orientation="Horizontal"
                    HorizontalAlignment="Center">
            <TextBlock Text="Views: "
                       VerticalAlignment="Center"/>
            <ComboBox ItemsSource="{Binding ViewTypes}"
                      SelectedItem="{Binding SelectedViewType}"/>

        </StackPanel>

        <ContentControl Grid.Row="1"
                        HorizontalAlignment="Stretch"
                        Content="{Binding CurrentViewModel}" />

        <TextBlock Grid.Row="2"
                   FontWeight="Bold"
                   Foreground="Red">
            <Run Text="Error: " />
            <Run Text="{Binding ErrorMessage}" />
        </TextBlock>
                   
    </Grid>
</Window>

MainViewModel


using System;
using System.Collections.Generic;
using System.Linq;

namespace Forum124378II
{
    public class MainWindowViewModel : ViewModelBase
    {
        private Navigator navigator;
        private ViewModelFactory viewModelFactory;
        private ViewModelTypes selectedViewType;
        private string errorMessage;

        public ViewModelBase CurrentViewModel
        {
            get { return navigator.CurrentViewModel; }
        }

        public string ErrorMessage
        {
            get { return errorMessage; }
            set
            {
                if (errorMessage != value)
                {
                    errorMessage = value;
                    OnPropertyChanged();
                }
            }
        }

        public IEnumerable<ViewModelTypes> ViewTypes
        {
            get
            {
                return Enum.GetValues(typeof(ViewModelTypes)).Cast<ViewModelTypes>();
            }
        }

        public ViewModelTypes SelectedViewType
        {
            get { return selectedViewType; }
            set
            {
                if (selectedViewType != value)
                {
                    selectedViewType = value;
                    OnPropertyChanged();
                    UpdateView();
                }
            }
        }

        public MainWindowViewModel()
        {
            navigator = new Navigator();
            viewModelFactory = new ViewModelFactory();

            navigator.StateChanged += ViewModelChanged;
            SelectedViewType = ViewModelTypes.Customers;
            navigator.CurrentViewModel = viewModelFactory.Get(SelectedViewType);
        }

        private void UpdateView()
        {
            navigator.CurrentViewModel = viewModelFactory.Get(SelectedViewType);
        }

        private void ViewModelChanged()
        {
            OnPropertyChanged(nameof(CurrentViewModel));
            if (CurrentViewModel is IMessage viewModelWithMessage)
            {
                ErrorMessage = viewModelWithMessage.Message;
            }
        }
    }
}

Navigator:


using System;

namespace Forum124378II
{
    public class Navigator
    {
        private ViewModelBase currentViewModel;

        public ViewModelBase CurrentViewModel
        {
            get
            {
                return currentViewModel;
            }
            set
            {
                currentViewModel = value;
                StateChanged?.Invoke();
            }
        }

        public event Action StateChanged;
    }
}

Wenn der Navigator ein neues ViewModel erhält, dann wird ein Event gefeuert.
Das MainViewModel hat dieses Event aboniert und reagiert darauf mit der Methode ViewModelChanged.
In der Methode wird die Eigenschaft CurrentViewModel aktualisiert, was einen Austausch des DataTemplates in der View zur Folge hat.
Weiterhin wird geprüft, ob das ViewModel die Schnittstelle IMessage implementiert.
Falls dem so ist, dann wird der Wert aus der Eigenschaft Message im CurrentViewModel in die Eigenschaft ErrorMessage geschrieben.

Thema: Wert aus Viewmodel an ein anderes Model/Viewmodel übergeben
Am im Forum: GUI: WPF und XAML

Servus,

ganz kann ich dem Code im Eingangspost nicht folgen.
Deshalb eine Eigenkreation, die vielleicht das gewünschte berwerkstelligt.
Wie von Th69 schon angemerkt, solltest Du eine Basisklasse für Deine ViewModels haben:


public class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged_Implementation
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }

Von dieser Basisklasse leiten die folgenden zwei Klassen ab:


    public class CustomerViewModel : ViewModelBase, IViewModelWithMessage
    {
        public string Message { get; private set; }

        public CustomerViewModel(int i)
        {
            Message = $"Customer {i} is greeting you!";
        }
    }


public class NonCustomerViewModel : ViewModelBase
    {
        public NonCustomerViewModel()
        {
            
        }
    }

Die CustomerViewModel Klasse implementiert auch das Interface für das Message-Property


public interface IViewModelWithMessage
    {
        string Message { get; }
    }

Erzeugt werden die konkreten Klassen im MainWindowViewModel


public class MainWindowViewModel : ViewModelBase
    {
        public int Index { get; set; }

        public List<ViewModelBase> ViewModels { get; set; }

        private string newMessage;

        public string NewMessage
        {
            get { return newMessage; }
            set
            {
                if (newMessage != value)
                {
                    newMessage = value;
                    OnPropertyChanged();
                }
            }
        }

        public ICommand MoveToNextViewModelCmd { get; }

        public MainWindowViewModel()
        {
            Index = 0;
            ViewModels = new List<ViewModelBase>();
            for (int i = 0; i < 2; i++)
            {
                ViewModels.Add(new CustomerViewModel(i));
            }
            for (int i = 0; i < 3; i++)
            {
                ViewModels.Add(new NonCustomerViewModel());
            }
            for (int i = 5; i < 10; i++)
            {
                ViewModels.Add(new CustomerViewModel(i));
            }
            MoveToNextViewModelCmd = new MoveToNextViewModelCommand(this);
        }
    }

Das zugehörige MainWindow

<Window x:Class="Forum.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:Forum"
        mc:Ignorable="d"
        Title="MainWindow">

    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    
    <StackPanel HorizontalAlignment="Center">
        <Button Content="Next" Command="{Binding MoveToNextViewModelCmd}" />
        <Label>Meldung:</Label>
        <TextBlock x:Name="txtMessage" Text="{Binding NewMessage}"/>
    </StackPanel>
</Window>

Beim Drücken auf den Button in der Mainview wird in der Kommando-Klasse der Text aus der Customer-Klasse in das MainWindowViewModel übertragen.


internal class MoveToNextViewModelCommand : ICommand
    {
        public event EventHandler? CanExecuteChanged;

        private ViewModelBase viewModel;

        public MoveToNextViewModelCommand(ViewModelBase anyViewModel)
        {
            viewModel = anyViewModel;
        }

        public bool CanExecute(object? parameter)
        {
            return true;
        }

        public void Execute(object? parameter)
        {
            if (viewModel is MainWindowViewModel mainViewModel)
            {
                if (mainViewModel.Index == mainViewModel.ViewModels.Count)
                {
                    mainViewModel.Index = 0;
                }
                if (mainViewModel.ViewModels[mainViewModel.Index] is IViewModelWithMessage viewModelWithMessage)
                {
                    mainViewModel.NewMessage = viewModelWithMessage.Message;
                }
                else
                {
                    mainViewModel.NewMessage = $"ViewModel at Index { mainViewModel.Index } is of type { mainViewModel.ViewModels[mainViewModel.Index] } and has therefore no Message-Property";
                }
                mainViewModel.Index++;
            }
        }
    }

Ich habe den Quellcode auch auf Github

Thema: Exchange 2022 Bug
Am im Forum: Smalltalk

Also das MS Exchange scheint ein einziger großer Bug zu sein. Was da alles hochkommt.
Das neueste: 2022-Bug

Thema: Style in Generic.xaml wird nicht zugewiesen
Am im Forum: GUI: WPF und XAML

Zitat von Palladin007
Ich persönlich habe noch nie eine "Generic.xaml" genutzt
Also wenn es für diesen speziellen Namen irgendwelche Sonderregelungen gibt, weiß ich nichts davon.

Diese zwei Sätze haben mir die Augen geöffnet, auch wenn wir da aneinander vorbei reden. Ich bin so ein Dödel. Hat mich jetzt keine 30 Minuten gekostet, das Projekt ans Laufen zu bekommen! Gestern ist mir das nach 10 Stunden Google-Suche und etlichen Gläsern Bowle nicht eingefallen.
Lösung: Der richtige Projekttyp ist wichtig. Statt "WPF-Klassenbibliothek" hätte ich "Bibliothek benutzerdefinierter WPF-Steuerelemente" auswählen müssen. Dann wird nämlich auch der Themes-Ordner mit Generic.xaml angelegt und verwendet!

Vielen Dank @Palladin007!

Thema: Style in Generic.xaml wird nicht zugewiesen
Am im Forum: GUI: WPF und XAML

Hallo,
ich habe begonnen, meine Controls unter Visual Studio 2022 aud .Net6 umzustellen. Dafür verwende ich ein eigenes Projekt (nur der Übung halber!).
Wie ich nun feststellen muss, wird der zum Control definierte Style aus der Generic.xaml nicht zugewiesen, so dass das komplette Control nicht sichtbar wird.
Google sagt, dass das früher schon immer mal ein Problem war und dass das an einem doppelten Generic.xaml liegen könnte. Die vorgeschlagenen Lösungen habe ich erfolglos durchprobiert. Wenn ich den kompletten Style im instantierten Control zuweise funktioniert alles.
Die Generic.xaml besteht nur aus einem ResourceDictionary, wo auf die xaml-Dateien für die einzelnen Controls verwiesen wird.

Hat hier jemand einen Tip?

Thema: Wie das Gerät zur Audiowiedergabe ändern?
Am im Forum: Rund um die Programmierung

Servus,

am einfachsten scheint mir das unter Verwendung des NuGet-Paketes CoreAudio realisierbar zu sein.
https://docs.microsoft.com/en-us/windows/win32/api/_coreaudio/ Die Dokumentation zur CoreAudioApi

Ein auf die Schnelle hingeschmierter Code:


using System;
using CoreAudio;

namespace AudioCore
{
    internal class Program
    {
        static MMDeviceCollection speakerList;
        static MMDevice activeSpeaker;


        static void Main(string[] args)
        {
            MMDeviceEnumerator deviceEnumerator = new();
            speakerList = deviceEnumerator.EnumerateAudioEndPoints(EDataFlow.eRender, DEVICE_STATE.DEVICE_STATE_ACTIVE);
            activeSpeaker = deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);

            foreach (MMDevice device in speakerList)
            {
                Console.WriteLine(device.FriendlyName);
                Console.WriteLine(device.ID);
                Console.WriteLine("--");
            }

            SetDefaultAudioDevice();

            Console.ReadKey();
        }

        static void SetDefaultAudioDevice()
        {
            MMDeviceEnumerator deviceEnumerator = new();
            foreach (MMDevice device in speakerList)
            {
                if (!device.ID.Equals(activeSpeaker.ID))
                {
                    deviceEnumerator.SetDefaultAudioEndpoint(device);
                    break;
                }
            }
        }
    }
}

Thema: Bindingfehler aber es bindet
Am im Forum: GUI: WPF und XAML

Ich vermute mal, dass die Bindungen dadurch zustande kommen, weil Du den DataContext vom DataTemplate direkt auf das ToolViewModel bindest. Wie Papst schon angemerkt hat, fehlt das Tools-Property im ViewModel.

In Deinem ViewModel musst Du ein Property Tools vom Typ List<ToolViewModel> definieren. Du brauchst in dem Fall keine ObservableCollection<ToolViewModel>, da sich die Anzahl der Tools nicht ändert.
Das DataTemplate ToolChangeView änderst Du wie folgt.


        <DataTemplate DataType="{x:Type local:ToolViewModel}">
            <views:ToolChangeView />
        </DataTemplate>

Du solltest auch überlegen, ob Du das ToolViewModel nicht verallgemeinern kannst. Tooldate und Basedaten haben beim KUKA die gleiche Struktur.

Hier nochmals als Code:

        <ListView x:Name="lstNewTool" 
                  ItemsSource="{Binding Tools}" 
                  ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                  ScrollViewer.VerticalScrollBarVisibility="Auto" 
                  SelectionMode="Single" 
                  Margin="5" 
                  Width="400">
            <ListView.ItemTemplate>
                <DataTemplate DataType="{x:Type local:ToolViewModel}">
                    <StackPanel>
                        <TextBlock Text="{Binding ToolName}" />
                        <TextBlock Text="{Binding ToolNumber}" />
                        <TextBlock Text="{Binding ToolData.X}" />
                        <TextBlock Text="{Binding ToolData.Y}" />
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>


    public class MainWindowViewModel : ViewModelBase
    {
        public ObservableCollection<ToolViewModel> Tools { get; set; }

        public MainWindowViewModel()
        {
            Tools = new ObservableCollection<ToolViewModel>
            {
                new ToolViewModel()
            };
        }
    }

Thema: c# Datum umwandeln?
Am im Forum: Grundlagen von C#

Zitat von Little Tester
Das zweite Beispiel mit "with leading white space" hat dann immerhin ein Ergebnis gegeben, aber nicht, das, was ich mir erhofft habe. Umwandeln klappte natürlich damit erst recht nicht.

22.06.2021 00:00:00 +00:00


                    string stringDate = managementObject["InstalledOn"].ToString();
                    string format = "M/dd/yyyy"; // M/d/yyyy geht auch
                    CultureInfo provider = CultureInfo.InvariantCulture;
                    DateTimeOffset result = new DateTimeOffset();
                    result = DateTimeOffset.ParseExact(stringDate, format, provider, DateTimeStyles.AssumeUniversal);
                    systemLastWindowsUpdate = result.ToString();

Und wenn Du die letzte Zeile wie folgt schreibst?


systemLastWindowsUpdate = result.ToString("yyyy-MM-dd");

Thema: Wie kann ich im WPF an Properties meiner Klasse binden?
Am im Forum: GUI: WPF und XAML

In der Regel wird alles im XAML definiert. Im MVVM Pattern wird normalerweise nichts, aber auch gar nichts im Code behind programmiert.
Und ich fürchte, du hast ein Verständnisproblem mit den View Models. Willst Du für jedes Steuerelement ein eigenes ViewModel machen? Also auch ein CheckBoxViewModel, RadioButtonViewModel, TextBlockViewModel, DataGridViewModel, ...?
Was müssen Deine ViewModels außergewöhnliches können - außer Text anzeigen - dass man dies so wie von Dir gewünscht, definieren müßte?
Ändert sich die Ansicht?

Thema: Wie kann ich im WPF an Properties meiner Klasse binden?
Am im Forum: GUI: WPF und XAML

Servus,

warum definierst Du den DataContext im XAML und im Code behind?

Thema: Kann man einer TextBox oder allgemein Steuerelementen neue Attribute zuweisen?
Am im Forum: GUI: WPF und XAML

Oder man verwendet dafür die Tag-Eigenschaft.

Thema: Spalten aus einer Exceltabelle zur Laufzeit zu einem Datagrid hinzuladen - Binding im ViewMode
Am im Forum: GUI: WPF und XAML

Hallo Th69,

es soll nach Möglichkeit eine beliebige Anzahl an Spalten hinzugefügt werden können.
Meine bisherige ItemsSource ist eine ObservableCollection von ViewModels, die eine Datenzeile repräsentieren - also ganz klassisch!
Die DataTable hatte ich gleich zu Beginn in betracht gezogen, dann aber ziemlich schnell verworfen, weil ich mehrfach gelesen habe, dass man diese nicht mehr verwenden sollte.
Werde mich aber am kommenden WE dann doch nochmals näher damit auseinandersetzen.

Thema: Spalten aus einer Exceltabelle zur Laufzeit zu einem Datagrid hinzuladen - Binding im ViewMode
Am im Forum: GUI: WPF und XAML

Hallo,

ich habe ein Datagrid, das einige fest definierte Spalten hat. Nun möchte ich gerne aus einer Exceltabelle willkürliche Spalten zur Laufzeit hinzuladen.
Das hinzuladen der Spalten an sich ist (im Moment) nicht das Problem. Seit ein paar Tagen mache ich mir aber Gedanken darüber, wie ich die Excelspalten mit meinem ViewModel verbinde, komme aber auf keine Lösung. Wie muss ich das angehen?

Thema: Wieso bekomme ich eine Index Exception beim Zugriff auf ein mehrdimanesionales Array?
Am im Forum: Grundlagen von C#

Dein Problem ist, dass Du mit

for (int j = 0; j < IntArray.Length; j++)
ebenfalls nur die erste Dimension abfrägst.

Ändere die innere Schleife, so dass die zweite Dimension abgefragt wird.

for (int j = 0; j < IntArray.GetLength(1); j++)

Thema: Wie implementiere ich einen Zurück-Button in einer App-Navigation mit MVVM?
Am im Forum: GUI: WPF und XAML

Hallo CombatKarl,

ich habe da mal eine Frage. Verwendest Du die Prism library?

public class MainVM : BindableBase
deutet jedenfalls darauf hin. Es gäbe nämlich in den Beispielprogrammen zu Prism mehrere Beispiele zur Navigation. Vielleicht helfen Dir diese weiter! Ich stand vor einigen Wochen vor dem gleichen Problem und mir haben diese Beispiele schon enorm geholfen.

Thema: Warum hat im C# & XAML ein Label hat immer eine 0 vor der eigentlichen Zahl?
Am im Forum: GUI: WPF und XAML

Hallo,

in Deinem XAML sind alle Buttons ausser der 0 und 1 tot, da kein Click Event definiert ist.
Die beiden Buttons 0 und 1 definieren das gleiche Event, aber die zugehörige Cmd_1_Click Methode hast Du nicht gepostet.
Stattdessen aber Cmd_0_Click, die aber keinem Button zugeordnet ist.
In Deiner Cmd_0_Click Methode wird nicht ersichtlich, welcher Button gedrückt ist und einfach immer nur stur eine weitere 0 im Label angefügt.

Deswegen verwende ich jetzt mal die Methode als Cmd_1_Click für eine mögliche Lösung:

        private void Cmd_1_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            if (lbl_rechenzeichen.Content == "")
            {
                Lbl_rechenoperator_1.Content = $"{Lbl_rechenoperator_1.Content}{button.Content}";
            }
            else
            {
                lbl_rechenoperator_2.Content = $"{lbl_rechenoperator_2.Content}{button.Content}";
            }
        }

Das ist jetzt WPF, da ich von Xamarin keinen Plan habe!