C
C#Davaaron

❔ WPF - Use command of viewmodel instead of item on click

Hi, I have a list of strings and display them as buttons. The list is held by a viewmodel and the viewmodel has a Command for the button click. Now, instead of creating an object for strings and add the Command to the items, I would like to have the Command at the viewmodel level.
<Grid x:Name="LayoutRoot" Margin="5">
<ItemsControl ItemsSource="{Binding Options}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding CloseDialogCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type vm:NotificationDialogViewModel}}}" CommandParameter="true" Content="{Binding }" MinWidth="75" Height="25" Margin="10,5,10,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<Grid x:Name="LayoutRoot" Margin="5">
<ItemsControl ItemsSource="{Binding Options}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding CloseDialogCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type vm:NotificationDialogViewModel}}}" CommandParameter="true" Content="{Binding }" MinWidth="75" Height="25" Margin="10,5,10,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
public class NotificationDialogViewModel : BindableBase, IDialogAware
{
private DelegateCommand<string> _closeDialogCommand;
public DelegateCommand<string> CloseDialogCommand =>
_closeDialogCommand ?? (_closeDialogCommand = new DelegateCommand<string>(CloseDialog));

protected virtual void CloseDialog(string parameter)
{
ButtonResult result = ButtonResult.None;

if (parameter?.ToLower() == "true")
result = ButtonResult.OK;
else if (parameter?.ToLower() == "false")
result = ButtonResult.Cancel;

RaiseRequestClose(new DialogResult(result, new DialogParameters($"parameter={parameter}")));
}

}
public class NotificationDialogViewModel : BindableBase, IDialogAware
{
private DelegateCommand<string> _closeDialogCommand;
public DelegateCommand<string> CloseDialogCommand =>
_closeDialogCommand ?? (_closeDialogCommand = new DelegateCommand<string>(CloseDialog));

protected virtual void CloseDialog(string parameter)
{
ButtonResult result = ButtonResult.None;

if (parameter?.ToLower() == "true")
result = ButtonResult.OK;
else if (parameter?.ToLower() == "false")
result = ButtonResult.Cancel;

RaiseRequestClose(new DialogResult(result, new DialogParameters($"parameter={parameter}")));
}

}
Davaaron
Davaaron354d ago
The error is: System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Davaaron.BankOverview.ViewModels.Dialogs.NotificationDialogViewModel', AncestorLevel='1''. BindingExpression:Path=CloseDialogCommand; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
HimmDawg
HimmDawg354d ago
Your AncestorType is a ViewModel. It's must always be a control tho
Davaaron
Davaaron354d ago
Oh okay.. so I have to add some kind of event to the items (buttons) and then listen in the NotificationDialogViewModel.. alright
Klarth
Klarth354d ago
Your VM method is a bit weird given it basically has the result twice: RaiseRequestClose(new DialogResult(result, new DialogParameters($"parameter={parameter}"))); But besides that, your binding isn't correct. Indirect bindings go through controls first. I prefer ElementName bindings here because they're simpler to write.
<Grid x:Name="LayoutRoot" Margin="5">
<ItemsControl x:Name="options" ItemsSource="{Binding Options}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding DataContext.CloseDialogCommand, ElementName=options}" CommandParameter="true" Content="{Binding}" MinWidth="75" Height="25" Margin="10,5,10,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<Grid x:Name="LayoutRoot" Margin="5">
<ItemsControl x:Name="options" ItemsSource="{Binding Options}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding DataContext.CloseDialogCommand, ElementName=options}" CommandParameter="true" Content="{Binding}" MinWidth="75" Height="25" Margin="10,5,10,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
So the Command binds to the ItemsControl, then into its DataContext (your VM...which I assume is the one you want?).
Davaaron
Davaaron354d ago
Thank you very much, that worked!! 🙂
Accord
Accord353d ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server
More Posts
❔ Error when deploy a webserviceHello everyone. I'm trying to fix this error when I deploy my app: The configured user limit (128) ✅ Recursive type definitionThis is valid (basically CRTP): ```csharp class Base<T> { } class Derived<T> : Base<Derived<T>> { } ❔ Covariant Interface ReturnIs there some reason why this doesn't work? I understand we can get this behavior with virtual metho❔ WPF Excel Help -I've made an entire post about the problem on C# subreddit. Here's the link to it : https://www.reddHow to do a 3 way merge on a file that has been moved after folder structure and refactoring change?The repo I am working in has been radically refactored. The folder structure has changed and a long ❔ I have a project that I need to submit in 6 hours, but I'm stuck at one point.Project: The project aims to develop a web interface where a minimum of 3 and a maximum of 5 people'❔ System.MissingMethodException: Entry point not found in assemblyHi i try to run an example program build inside my library. When i run the debuger (Visual Studio C✅ run async funtion from constructorwe can't use await keyword in the constructor because we can't add `async` keyword to it. How to run❔ tls 1.2 serverI'm the server and for some weird reason other than the server certificate I also have to send right❔ Wifi p2p in dotnet core for Windows / Androidi have no idea what library to look on , any hint❔ Validate CADESignatureHello guys, Can you please help me with getting this resolved, I have an integration with a third-✅ DI with HttpClient / HttpClientFactoryThe docs show the basic usage of HttpClientFactory with DI as follows: ```cs public class SomeServic❔ IHealthCheck and SwaggerHello. I'm experimenting with the interface `IHealthCheck` in my Web Service. I used to have a endpo❔ CookieContainer and IHttpClientFactoryHello, I'm currently migrating some old code base (.Net Core 3.0), and the code itself has a bunch o❔ how can I change this code to higher language in WPF C#i'm new and i don't know how to change this i tried alot of ways but it still get me errors❔ Entity framework custom select queryI want to get result for the following query in EF ```sql SELECT OBJECT_NAME(fk.parent_object_i❔ ✅ JSON Serialization not working?Can someone help me with this one, in the MS docs this seems to work just fine, what am i doing wron❔ Microsoft.Data.SqlClient.SqlExceptionMicrosoft.Data.SqlClient.SqlException: 'A connection was successfully established with the server, b❔ Cannot start OmniSharp due to error on MacOSThe error said I haven't install `.NET 6 SDK for arm64` even though I tried to install it TWICE. I c❔ avalonia datagrid dynamic columnsI'm trying to create a mongodb client with Avalonia UI, I want to dynamically create columns in a da