Hallo zusammen,
Nach dem mich der ErfinderdesRades überzeugt hat das das MVVM Pattern und WPF einfach gut zusammenpassen hab ich mein komplettes Testprogramm neu geschrieben ich habe versucht das MVVM komplett durchzuziehen dazu habe ich ein paar Verständnisfragen und auch ein paar Problemchen ich packe das alles in diesen Thread rein.
Problem 1: Einbindung des MainModels in die Applikation
Das Mainmodel bzw. die Klasse wird ja in der Application.xaml als Application Resource eingebunden:
in der Error List bringt er mir aber diese Meldung:
In der app.config ist aber der Connection String hinterlegt und das Programm funktioniert auch:
Ich habe schon rumgesucht anscheinend muss man den ConnectionString kopieren oder so aber irgendwie werd ich da nicht ganz schlau?
Verständnisfragen
Das MVVM Pattern ist mir soweit klar ich habe ein Modell das die Daten definiert, ein Viewmodel das eine Art Controller ist und die Logik bereitstellt sowie die View die alles präsentiert soweit so gut.
Beim Entity Framework werden die Entitäten als Klassen implementiert => Viewmodel
Das MainModel ist eine weitere Klasse die die Logik stellt hier fahren alle Entitäten als Listen zusammen und werden bearbeitet (CRUD)
Ist das soweit korrekt?
das führt nun zu meinem 2. Problem
Ich greife mir jetzt mal eine Entität aus meinem Modell heraus:
trans_status_v01 eine simple Tabelle mit einigen wenigen Propertys.
Im Mainmodel habe ich jetzt das "Viewmodel" eingebunden (der Übersichtlichkeit halber Zeige ich hier nur die Region die die Entität betrifft:
Ich überlade also das Viewmodel in eine ObservableCollection __transstatus diese wiederum sollte dem Beispiel von EdR folgend (EFMostSimple) eine ListCollectionView "synchronisieren" was es nicht tut, das wiederum liegt wie mir EdR erklärt hat daran das die transstati() nichts von der Änderung in der OCol __transstatus mitbekommt wegen der Bindung dafür habe ich noch keine Lösung gefunden derzeit binde ich einfach alles an die __transstatus Collection das funktioniert soweit auch recht gut.
Nun habe ich mir eine View gebastelt die Links eine Listview beinhaltet und rechts Textfelder usw. für die Propertys:
In diese Bind ich mein Mainmodel ein und Binde die Listview an die Collection, das Stackpanel hat den Datacontext und das ganze ist synchronisiert. Soweit so gut funktioniert hier ergeben sich für mich wiederum 2 Probleme:
Wähle ich in der Listview ein Element aus und Editiere es dann im Stackpanel z.b. Namensänderung speichert er mir das sofort synchronisiert aber nicht die Listview wie eigentlich gewünscht erst wenn ich in der Listview einen Eintrag neu wähle und zurückspringe...
Ähnliches Problem ergibt sich bei meinem Command cmdColorTransStatus dieses wird über einen Button aufgerufen holt einen Colorpicker Dialog und schreibt ihn zurück in die Collection funktioniert auch ganz gut aber hier bekommt die Textbox die an die Property color gebunden ist nichts davon mit
Lustigerweise werden die Änderungen aber sofort in der Collection übernommen (nicht zurück in die Datenbank) aber der User hat damit keine Möglichkeit seine Änderungen rückgängig zu machen....
Ich habe schon versucht das EF Model um die Hilfsklasse PropertyChanged zu erweitern aber auch das funktioniert nicht.
Tut mir leid das der Thread mega lange ist aber ich versuche wirklich das Thema MVVM zu verstehen und es vernünftig einzusetzen
Nach dem mich der ErfinderdesRades überzeugt hat das das MVVM Pattern und WPF einfach gut zusammenpassen hab ich mein komplettes Testprogramm neu geschrieben ich habe versucht das MVVM komplett durchzuziehen dazu habe ich ein paar Verständnisfragen und auch ein paar Problemchen ich packe das alles in diesen Thread rein.
Problem 1: Einbindung des MainModels in die Applikation
Das Mainmodel bzw. die Klasse wird ja in der Application.xaml als Application Resource eingebunden:
in der Error List bringt er mir aber diese Meldung:
Error No connection string named 'data_modelContainer' could be found in the application config file.
In der app.config ist aber der Connection String hinterlegt und das Programm funktioniert auch:
XML-Quellcode
- <connectionStrings>
- <add name="data_modelContainer" connectionString="metadata=res://*/Model.data_model.csdl|res://*/Model.data_model.ssdl|res://*/Model.data_model.msl;provider=System.Data.SqlClient;provider connection string="data source=.\SQLEXPRESS;initial catalog=hhhb_template2;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
- </connectionStrings>
Ich habe schon rumgesucht anscheinend muss man den ConnectionString kopieren oder so aber irgendwie werd ich da nicht ganz schlau?
Verständnisfragen
Das MVVM Pattern ist mir soweit klar ich habe ein Modell das die Daten definiert, ein Viewmodel das eine Art Controller ist und die Logik bereitstellt sowie die View die alles präsentiert soweit so gut.
Beim Entity Framework werden die Entitäten als Klassen implementiert => Viewmodel
Das MainModel ist eine weitere Klasse die die Logik stellt hier fahren alle Entitäten als Listen zusammen und werden bearbeitet (CRUD)
Ist das soweit korrekt?
das führt nun zu meinem 2. Problem
Ich greife mir jetzt mal eine Entität aus meinem Modell heraus:
trans_status_v01 eine simple Tabelle mit einigen wenigen Propertys.
VB.NET-Quellcode
- Partial Public Class trans_status_v01
- Public Property status_id As Integer
- Public Property bezeichnung As String
- Public Property color As String = "#000000"
- Public Property symbol As Nullable(Of Byte)
- Public Property aktiv As Boolean = true
- Public Overridable Property nv_transstatus_trans As ICollection(Of transactions_v01) = New HashSet(Of transactions_v01)
- End Class
Im Mainmodel habe ich jetzt das "Viewmodel" eingebunden (der Übersichtlichkeit halber Zeige ich hier nur die Region die die Entität betrifft:
VB.NET-Quellcode
- #Region "Buchung:Status"
- #Region "Commands"
- Public Property cmdAddTransStatus() As New RelayCommand(Sub() Transstati.AddNewItem(New trans_status_v01() With {.bezeichnung = "<New Status>"}), Function() True)
- Public Property cmdSaveTransStatus() As New RelayCommand(AddressOf TransStatusSave, Function() __transstatus.Count > 0)
- Public Property cmdColorTransStatus() As New RelayCommand(AddressOf TransStatusColor, Function() __transstatus.Count > 0)
- #End Region
- Public WithEvents __transstatus As New ObservableCollection(Of trans_status_v01)()
- Public Property Transstati() As New ListCollectionView(__transstatus)
- Private Sub TransStatusLoad()
- __transstatus.Clear()
- dbo.trans_status_v01.Load
- __transstatus = dbo.trans_status_v01.Local
- Transstati.MoveCurrentToFirst()
- Debug.Print(__transstatus.Count.ToString)
- Debug.Print(Transstati.Count.ToString)
- End Sub
- Private Sub TransStatusSave()
- Debug.Print(__transstatus.Count.ToString())
- dbo.SaveChanges()
- End Sub
- ''' <summary>
- ''' Behandelt das ändern der Schriftfarbe für ein Objekt vom Typ TransStatus
- ''' </summary>
- Private Sub TransStatusColor()
- Dim v_color As Color = get_color_from_dialog()
- If Not v_color = Nothing Then
- Dim v_helper = CollectionViewSource.GetDefaultView(__transstatus.ToList)
- Dim v_transstatus As trans_status_v01 = CType(v_helper.CurrentItem, trans_status_v01)
- v_transstatus.color = v_color.ToString
- End If
- End Sub
- Private Sub __transstatus_CollectionChanged(sender As Object, e As Specialized.NotifyCollectionChangedEventArgs) Handles __transstatus.CollectionChanged
- If e.Action <> Specialized.NotifyCollectionChangedAction.Remove Then Return
- If Not Transstati.MoveCurrentToNext Then Transstati.MoveCurrentToPrevious()
- End Sub
- #End Region
Ich überlade also das Viewmodel in eine ObservableCollection __transstatus diese wiederum sollte dem Beispiel von EdR folgend (EFMostSimple) eine ListCollectionView "synchronisieren" was es nicht tut, das wiederum liegt wie mir EdR erklärt hat daran das die transstati() nichts von der Änderung in der OCol __transstatus mitbekommt wegen der Bindung dafür habe ich noch keine Lösung gefunden derzeit binde ich einfach alles an die __transstatus Collection das funktioniert soweit auch recht gut.
Nun habe ich mir eine View gebastelt die Links eine Listview beinhaltet und rechts Textfelder usw. für die Propertys:
XML-Quellcode
- <Window x:Class="dia_verw_trans_status"
- 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:HHHB2"
- mc:Ignorable="d"
- Title="Buchung: Status" Height="300" Width="450" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner"
- DataContext="{Binding Source={StaticResource Mainmodel}}">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="25"/>
- <RowDefinition/>
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="150"/>
- <ColumnDefinition/>
- </Grid.ColumnDefinitions>
- <StackPanel x:Name="stackPanel" Orientation="Horizontal" DockPanel.Dock="Top">
- <StackPanel.Background>
- <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
- <GradientStop Color="#FFAEAEAE" Offset="1"/>
- <GradientStop Color="#FFAEAEAE"/>
- <GradientStop Color="#FFC7C7C7" Offset="0.5"/>
- </LinearGradientBrush>
- </StackPanel.Background>
- <Button Margin="1" ToolTip="Erstellen" Background="{x:Null}" BorderBrush="{x:Null}" Command="{x:Static local:central_commands.Folder_Add_Edit}">
- <Image Source="/Resources/Images/but_add.png" />
- </Button>
- <Button Margin="1" ToolTip="Bearbeiten" Background="{x:Null}" BorderBrush="{x:Null}">
- <Image Source="/Resources/Images/but_edit.png" />
- </Button>
- <Button Margin="1" ToolTip="Löschen" Background="{x:Null}" BorderBrush="{x:Null}">
- <Image Source="/Resources/Images/but_delete.png" />
- </Button>
- </StackPanel>
- <ListView x:Name="lvw_status" Grid.Column="0" Grid.Row="1" ItemsSource="{Binding __transstatus}" DisplayMemberPath="bezeichnung" IsSynchronizedWithCurrentItem="True"></ListView>
- <StackPanel Grid.Column="1" Grid.RowSpan="2" DataContext="{Binding __transstatus/, Mode=TwoWay, UpdateSourceTrigger=Default}">
- <DockPanel>
- <Label x:Name="lbl_bezeichnung" Margin="3" Content="Bezeichnung" DockPanel.Dock="Left"/>
- <TextBox x:Name="txt_bezeichnung" Margin="3" DockPanel.Dock="Left" Text="{Binding bezeichnung}"/>
- </DockPanel>
- <DockPanel>
- <Label Margin="3" Content="Farbe" DockPanel.Dock="Left" Width="{Binding ActualWidth, ElementName=lbl_bezeichnung, Mode=OneWay}"/>
- <Button Command="{Binding Source={StaticResource Mainmodel},Path=cmdColorTransStatus}" Margin="3" Width="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}}">
- <Image Source="/HHHB2;component/Resources/Images/search.png"/>
- </Button>
- <TextBox x:Name="txt_color" Margin="3" DockPanel.Dock="Left" Text="{Binding color, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
- </DockPanel>
- <DockPanel LastChildFill="False">
- <Label Margin="3" Content="Symbol" DockPanel.Dock="Left" Width="{Binding ActualWidth, ElementName=lbl_bezeichnung, Mode=OneWay}"/>
- <Button x:Name="cmd_search_image" Margin="3" DockPanel.Dock="Left" Width="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}}">
- <Image Source="/HHHB2;component/Resources/Images/search.png"/>
- </Button>
- <Border Margin="3" Background="Gainsboro" Width="24" Height="24">
- <Image x:Name="img_symbol" Width="24" Height="24" Stretch="Fill"/>
- </Border>
- </DockPanel>
- <DockPanel>
- <Label Margin="3" Content="Aktiv" DockPanel.Dock="Left" Width="{Binding ActualWidth, ElementName=lbl_bezeichnung, Mode=OneWay}"/>
- <CheckBox VerticalAlignment="Center" Margin="3" DockPanel.Dock="Left" IsChecked="{Binding aktiv}"/>
- </DockPanel>
- <DockPanel LastChildFill="False" HorizontalAlignment="Right">
- <Button Margin="5,0,2,0" DockPanel.Dock="Right" Content="Abbrechen" MinWidth="65" IsCancel="True"/>
- <Button Margin="0" DockPanel.Dock="Right" Content="Speichern" MinWidth="70" IsDefault="True" Command="{Binding Source={StaticResource Mainmodel},Path=cmdSaveTransStatus}"/>
- </DockPanel>
- </StackPanel>
- </Grid>
- </Window>
In diese Bind ich mein Mainmodel ein und Binde die Listview an die Collection, das Stackpanel hat den Datacontext und das ganze ist synchronisiert. Soweit so gut funktioniert hier ergeben sich für mich wiederum 2 Probleme:
Wähle ich in der Listview ein Element aus und Editiere es dann im Stackpanel z.b. Namensänderung speichert er mir das sofort synchronisiert aber nicht die Listview wie eigentlich gewünscht erst wenn ich in der Listview einen Eintrag neu wähle und zurückspringe...
Ähnliches Problem ergibt sich bei meinem Command cmdColorTransStatus dieses wird über einen Button aufgerufen holt einen Colorpicker Dialog und schreibt ihn zurück in die Collection funktioniert auch ganz gut aber hier bekommt die Textbox die an die Property color gebunden ist nichts davon mit
Lustigerweise werden die Änderungen aber sofort in der Collection übernommen (nicht zurück in die Datenbank) aber der User hat damit keine Möglichkeit seine Änderungen rückgängig zu machen....
Ich habe schon versucht das EF Model um die Hilfsklasse PropertyChanged zu erweitern aber auch das funktioniert nicht.
Tut mir leid das der Thread mega lange ist aber ich versuche wirklich das Thema MVVM zu verstehen und es vernünftig einzusetzen
mfG.
Stephan
Stephan