Hallo Abt, danke für deine Antwort. Jetzt werde ich weiterkommen 🙂
Dein Constants.NotAvailable; ist übrigens so nen relativ übler Code Smell 😉
Da wirst du recht haben, ich gelobe Besserung.
Liebe Grüße
Hallo Alf,
danke für deine Antwort. Ich habe nach weiteren Überlegungen deinen Ratschlag befolgt und es umgesetzt. Du hattest Recht, so funktioniert es. Allerdings dachte ich man würde solche "ViewLogik" nicht in die Models packen. Also habe ich noch etwas rumprobiert und einfach nur mal den record in eine Klasse umgewandelt. Und siehe da, es funktioniert, ohne ObservableObject as parent. Wie kann ich mir das erklären?
public record Action() : IAction
{
public string Id { get; set; } = Constants.NotAvailable;
public long Timestamp { get; set; } = 0L;
public string Value { get; set; } = Constants.NotAvailable;
}
Hallo Alf,
danke für deine Rückfrage. Ich würde gerne meinen ersten Beitrag bearbeiten, finde aber keine Option dazu. Den DataTemplateSelector kann man ignorieren, er ist bezüglich der Fragestellung unrelevant.
Hier nochmal die aktualisierten Klassen von mir
<Page ...HistoryPage
d:DataContext="{d:DesignInstance HistoryPage, IsDesignTimeCreatable=False}"
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="9*"></RowDefinition>
<RowDefinition Height="1*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"></ColumnDefinition>
<ColumnDefinition Width="4*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding ViewModel.Actions, Mode=TwoWay}"
SelectedItem="{Binding ViewModel.SelectedAction, Mode=TwoWay}">
</ListView>
<MyUserControl1 Grid.Column="1" Action="{Binding ViewModel.SelectedAction, Mode=TwoWay}"/>
</Grid>
...
</Grid>
</Page>
HistoryViewModel.cs
public partial class HistoryViewModel : ObservableObject, INavigationAware
{
....
public ObservableCollection<IAction> Actions { get; set; } = new();
[ObservableProperty] private IAction _selectedAction;
public HistoryViewModel()
{
}
...
}
Action.cs
public record Action() : IAction
{
public string Id { get; set; } = Constants.NotAvailable;
public long Timestamp { get; set; } = 0L;
public string Value { get; set; } = Constants.NotAvailable;
}
Und hier die aktualisierte Fassung meiner MyUserControl1.xaml
<UserControl ...MyUserControl1
...
d:DataContext="{d:DesignInstance m:MyUserControl1, IsDesignTimeCreatable=False}"
...
>
<StackPanel DataContext="{Binding Path=Action, RelativeSource={RelativeSource AncestorType=UserControl}}">
<local:LabeledInputUserControl Description="Id" Input="{Binding Id, UpdateSourceTrigger=PropertyChanged}"/>
<local:LabeledInputUserControl Description="Timestamp" Input="{Binding Timestamp}"/>
<local:LabeledInputUserControl Description="Value" Input="{Binding Value}"/>
</StackPanel>
</UserControl>
MyUserControl1.xaml.cs
public partial class MyUserControl1: UserControl
{
public static DependencyProperty ActionProperty = DependencyProperty.Register(nameof(Action), typeof(Action), typeof(MyUserControl1), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public Action Action
{
get => (Action)GetValue(ActionProperty);
set => SetValue(ActionProperty , value);
}
public MyUserControl1()
{
InitializeComponent();
}
}
Wenn ich ein Item auswähle werden die Properties im UserControl angezeigt, sobald ich dort Werte abändere ist es mir nicht mehr möglich ein anderes Item auszuwählen, sprich das SelectedItem wird nicht mehr geändert. Wenn ich nichts ändere funktioniert es. Ich habe schon verschiedene UpdateSourceTrigger ausprobiert, komme da aber nicht weiter. Ich hoffe so ist es für dich ersichtlicher.
Liebe Grüße
Hallo zusammen,
ich würde gerne in einer Page mit einer ListView und einem ContentControl die SelectedItems der ListView in einem von mir erstellten UserControl anzeigen und bearbeiten.
Dazu möchte ich per DataTemplates die zum Typen zugehörigen UserControls laden.
HistoryPage.xaml
<Page ...HistoryPage
d:DataContext="{d:DesignInstance HistoryPage, IsDesignTimeCreatable=False}"
<Page.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type MyType1}">
<MyUserControl1/>
</DataTemplate>
<DataTemplate DataType="{x:Type MyType2}">
<MyUserControl2/>
</DataTemplate>
</ResourceDictionary>
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="9*"></RowDefinition>
<RowDefinition Height="1*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"></ColumnDefinition>
<ColumnDefinition Width="4*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding ViewModel.Actions}"
ItemTemplateSelector="{StaticResource MyDataTemplateSelector}"
SelectedItem="{Binding ViewModel.SelectedAction}">
</ListView>
<ContentControl Grid.Column="1" Content="{Binding Path=ViewModel.SelectedAction}"/>
</Grid>
...
</Grid>
</Page>
HistoryPage.xaml.cs
public partial class HistoryPage : INavigableView<HistoryViewModel>
{
public HistoryViewModel ViewModel {
get;
}
public HistoryPage(HistoryViewModel viewModel)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
}
}
HistoryViewModel.cs
public partial class HistoryViewModel : ObservableObject, INavigationAware
{
private bool _isInitialized = false;
[ObservableProperty] private ObservableCollection<IAction> _actions = new();
[ObservableProperty] private IAction _selectedAction;
public HistoryViewModel()
{
}
...
}
So schaffe ich es schonmal das zugehörige UserControl zu laden. Bearbeiten kann ich noch nichts, da ich relativ neu in WPF und dem "neuen C#" bin scheine ich etwas zu übersehen. Hier ist mein Usercontrol zum bearbeiten eines Types:
MyUserControl1.xaml
<UserControl ...MyUserControl1
...
d:DataContext="{d:DesignInstance m:MyUserControl1, IsDesignTimeCreatable=False}"
...
>
<StackPanel>
<local:LabeledInputUserControl Description="Id" Input="{Binding Id, UpdateSourceTrigger=PropertyChanged}"/>
<local:LabeledInputUserControl Description="Timestamp" Input="{Binding Timestamp}"/>
<local:LabeledInputUserControl Description="Value" Input="{Binding Amount}"/>
</StackPanel>
</UserControl>
public partial class MyUserControl1 : UserControl
{
public TransactionUserControl()
{
InitializeComponent();
DataContext = this;
}
}
Und hier mein UserControl zur Eingabe von Werten:
LabeledInputUserControl.xaml
<UserControl ... LabeledInputUserControl
d:DataContext="{d:DesignInstance local:LabeledInputUserControl, IsDesignTimeCreatable=False}"
....>
<WrapPanel HorizontalAlignment="Stretch" Width="300" Height="Auto">
<Label Content="{Binding Description, FallbackValue=Description, TargetNullValue=Description}"
Width="120"
Height="Auto"
Style="{StaticResource TextBoxLabel}"/>
<TextBox Text="{Binding Input}" Width="180" Height="Auto"/>
</WrapPanel>
</UserControl>
LabeledInputUserControl.xaml.cs
public partial class LabeledInputUserControl
{
public string Description { get; set; }
public static DependencyProperty InputProperty = DependencyProperty.Register(nameof(Input), typeof(string), typeof(LabeledInputUserControl), new PropertyMetadata());
public string Input
{
get => (string)GetValue(InputProperty);
set => SetValue(InputProperty, value);
}
public LabeledInputUserControl()
{
InitializeComponent();
DataContext = this;
}
}
Wie kann ich es so binden, dass ich das wie oben beschrieben bewerkstelligen kann?
Liebe Grüße