C# WPF New Window on ListView item double click - c#

I have a list view that is populated from a mysql table, I want to be able to double click on a item in the listview and bring up a new window with more information. How do I pass the first column value to the new window (this is the id of the item)? This way I can make another query to get the rest of the info about the item.

Was having a similar issue with a ListBox wanting to open a window (Different View) with the SelectedItem as the context (in my case, so I can edit it).
The three options I've found are:
1. Code Behind
2. Using Attached Behaviors
3. Using Blend's i:Interaction and EventToCommand using MVVM-Light.
I went with the 3rd option, and it looks something along these lines:
<ListBox x:Name="You_Need_This_Name"
ItemsSource="{Binding Your_Collection_Name_Here}"
SelectedItem="{Binding Your_Property_Name_Here, UpdateSourceTrigger=PropertyChanged}"
... rest of your needed stuff here ...
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<Command:EventToCommand Command="{Binding Your_Command_Name_Here}"
CommandParameter="{Binding ElementName=You_Need_This_Name,Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
That's about it ... when you double click on the item you want, your method on the ViewModel will be called with the SelectedItem as parameter, and you can do whatever you want there :)

What is meant with MVVM is that you will have for example a ViewModel containing a property SelectedThing bound to the SelectedItem of the listview and a command that gets executed using EventCommand on the MouseDoubleClick event of the View which will execute in the end the operation you want on the SelectedThing which could be also passed in as parameter to the command also by binding.

Related

How to pass the ViewModel instance into a user defined Command

Tips: Chinese content is just a translation of English content, you don't need to care about them, and please don't delete them
提示: 英文内容只是中文内容的翻译, 你不需要关心它们, 也请不要删掉它们
Knowing that I now have an MVVM MAUI project. There is a BindingList<string> Names property in the ViewModel, which generates controls in the view like this:
已知我现在有一个 MVVM 的 MAUI 项目. 在 ViewModel 中有一个 BindingList<string> Names 属性, 它会在视图中这样进行生成控件:
<CollectionView ItemsSource="{Binding Names}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I want after each item, there is a Button that can be used to delete the current item, and the Button logic is called via Command.
That is to say, in the logic of this Command, operate the Names property in ViewModel and delete one of them, so this Command needs to be passed into ViewModel
我希望在每一项后, 都有一个 Button 可以用来删除当前项, 并且 Button 逻辑通过 Command 调用.
也就是说, 这个 Command 的逻辑中, 操作 ViewModel 中的 Names 属性, 删除其中一项, 所以这个 Command 需要传入 ViewModel
Normally, if you declare the Command directly in the ViewModel, and then instantiate it, create a new Command and pass in the current ViewModel object, so that the Command can manipulate the Names in the ViewModel
正常来讲, 如果直接在 ViewModel 中声明这个 Command, 然后实例化的时候, 新建 Command 并传入当前 ViewModel 对象, 这样 Command 就可以操作这个 ViewModel 中的 Names
However, for CollectionView, his DataTemplate binding cannot be bound to the properties of the BindingContext set by Page, and his BindingContext is each item in Names. In this way, the instance of Command cannot be obtained.
但是, 对于 CollectionView, 他的 DataTemplate 绑定是无法绑定到 Page 设定的 BindingContext 的属性的, 他的 BindingContext 是 Names 中的每一项. 这样就拿不到 Command 的实例
If you define it in Resource, you can get the Command instance through StaticResource, but how does ViewModel pass in this Command?
如果通过在 Resource 中定义的话, 倒是可以通过 StaticResource 来拿到 Command 实例, 但是, ViewModel 改如何传入这个 Command 呢?
I want to achieve this using MVVM design pattern
我想要使用 MVVM 设计模式实现这一目的
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MyViewModel}}, Path=DetailsCommand}"
You want this.
Edit: To clarify. You are tapping on a DataTemplate bound to specific model. With this you are telling to go search a parent of this what you are tapping (your ViewModel) and use its command. (Since your Model doesn't have any commands).
First, I noticed that you want to use the MVVM, so you can use the ObservableCollection instead of using BindingList. You can refer to this article about ObservableCollection.
Second, you can use the relative-bindings as the solution.
<Button Text="Delete"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:MainPageViewModel}}, Path=DeleteItemCommand}"
CommandParameter="{Binding}"/>
Third, you can also set a name for your page and bind the name to your button source.
<Button Text="Delete" Command="{Binding BindingContext.DeleteCommand, Source={x:Reference MainPage}}" CommandParameter="{Binding .}" />
I hope I got your problem right.
The way out of the textbook:
Don't use "Binding Names" but bind to ViewModels again. The default should always be to bind to ViewModels.
But sometimes for me this was too much work and what you can do is to use the DataContext of a parent element. The nicest way for me it to give the root element a name and bind to this like:
{Binding DataContext.YourProperty, ElementName=YourRootElement}
With CommandParameter={Binding} you get your element.
[edit] You can also use FindAnchestor, but personally I don't likethat as it easily breaks when you change your XAML structure.
[edit2] It seems MAUI does not support binding by ElementName, at least I couldn't find it. So you will have to use the anchestor binding type https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/data-binding/relative-bindings#bind-to-an-ancestor
PS: Use BindingList only if your really need it, otherwise use ObservableCollection

Winrt triggers and Gridview ItemClick event

I am having trouble and don't know what to pass as command parameter.
<triggers:Interactions.Triggers>
<triggers:EventTrigger EventName="ItemClick">
<triggers:InvokeCommandAction Command="{Binding MenuItemClick}" CommandParameter=""/>
</triggers:EventTrigger>
</triggers:Interactions.Triggers>
This is inside gridview declaration. I want to recieve gridview clicked item in binded delegate as parameter.
You can set the PassEventArgsToCommand property of the InvokeCommandAction to true which will allow to pass ItemClickEventArgs pp to your command.
<triggers:InvokeCommandAction
Command="{Binding MenuItemClick}" PassEventArgsToCommand="True"/>
or see this article which provides more reliable solution from view point of better design.

Silverlight MultiBinding with a converter, converter not firing after OnPropertyChange

I'm having some issues when using a converter with multiple bindings in a Silverlight project. The task is to disable a button when it is clicked, depending how four properties are evaluated in the custom converter.
The flow of the task is as follows:
Converter fired when initialising buttons
Button clicked and Command fired in ViewModel
Keep a record of the Id of the button in one viewModel property
In ViewModel fire OnPropertyChanged for one of the three view model properties
This should fire the converter
Everything is working apart from the last step. During the second last step, I can see the Property being accessed again after the OnPropertyChanged is fired. So I can't understand why the binding doesn't pick this change up and fire the converter. I'm thinking it may be due to the button item being in a datagrid and the bindings using Path & ElementName.
I'm using a MultiBinding solution for Silverlight 5 from here.
And I've seen this question but its solution isn't available in Silverlight (Binding.IndexerName).
So on the actual control I have a datagrid where each row has a textblock and a button.
The Button IsEnabled is bound to a Converter with three values from the ViewModel (properties A-C) and one from the datagrid.ItemSource (Id).
<Button Tag="{Binding Id}"
IsEnabled="{multibinding:MultiBinding Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
Source1={Binding Path=DataContext.PropertyA, ElementName=LayoutRoot},
Source2={Binding Path=DataContext.PropertyB, ElementName=LayoutRoot},
Source3={Binding Id},
Source4={Binding Path=DataContext.PropertyC, ElementName=LayoutRoot},
Converter={StaticResource myConverter}}">
The Button Click event is bound to a command on my viewModel.
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path=DataContext.ClickCommand, ElementName=LayoutRoot}"
CommandParameter="{Binding Id}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Firing the OnPropertyChanged event in viewModel
public void OnClickCommand(int Id)
{OnPropertyChanged("PropertyA");}
I've actually just put a hack in place to refresh the whole control which will reinitialise and re-fire the converter but any help to solve this would be much appreciated.

How to detect Pivot View using MVVM in WP7?

basically I have a pivot control in my WP7 app that contains 3 views. On each view I'm calling 1 of my 3 different web services that I run. What I'm trying to do is call the service only when they navigate to that particular view.
It's pretty simple using the code behind because all you do is use selected index with a switch statement and you can fire certain methods accordingly. Any idea on how to accomplish this from a view model?
NOTE: I'm using MVVM Light.
UPDATE: Here's my code that I would normally use:
private void PivotItem_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int currentPivot = ResultsPivot.SelectedIndex;
switch (currentPivot)
{
case 0:
//Fire Method 1
break;
case 1:
//Fire Method 2
break;
case 2:
//Fire Method 3
break;
default:
//Fire default method
break;
}
}
The standard approach with MVVMLight is the split your view-model into data and commands. Most things you use databinding related, properties, etc. but commands actually do something.
In this case what you are calling "Fire Method 1" is an ordinary method that to conform to the pattern you have to convert to a command. If you already have commands you know what I am talking about.
The glue for events like SelectionChanged that you would have wired up with code-behind in MVVMLight is EventToCommand which is a XAML fragment that you put in the XAML with the pivot item instead of in the event hander.
So this is the pattern: EventToCommand is your key to hooking up XAML events to view-model commands without any code-behind. The best thing to do is use the MVVMLight samples to see how EventToCommand works because there are lots of ways to use it.
But here is the bare-bones version:
<controls:PivotItem Name="pivotItem">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectServiceCommand}"
CommandParameter="{Binding SelectedIndex, ElementName=pivotItem}"/>
</i:EventTrigger>
<!-- other stuff -->
</i:Interaction.Triggers>
</controls:PivotItem>
and to make this work the SelectServiceCommand has to actually exist in the view-model and it has to take a parameter and do the right thing for 0, 1, 2, 3, etc.
This can be solved in the following way
<controls:Pivot x:Name="PivotControl" FontSize="18" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="SelectionChanged">
<GalaSoft_MvvmLight_Command:EventToCommand x:Name="VideoPivotClicked"
Command="{Binding VideoPivotClicked, Mode=OneWay}" PassEventArgsToCommand="True" />
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
Then in your viewmodel you add this
public RelayCommand<SelectionChangedEventArgs> VideoPivotClicked
{
get;
private set;
}
VideoPivotClicked = new RelayCommand<SelectionChangedEventArgs>(arg =>
{
PivotItem pivotItem = arg.AddedItems[0] as PivotItem;
Pivot pivot = pivotItem.Parent as Pivot;
Debug.WriteLine(pivot.SelectedIndex);
}
);
You will not get the PivotItem that you are going to! and not the one you are leaving.
I haven't used MVVM Light directly, but you should be able to bind the selected index / item to a property on the view model. When that property is changed you could do your switch.
I like to keep things simple in situations like these where the View needs to notify the ViewModel that something that is so trivial changed (for example: A trivial combobox selection change that really has nothing to do with the view state (i.e ViewModel)).
For your specific case, in your switch statement, just call a public method in your ViewModel.
How to get the viewmodel reference? You can obtain that by the view's DataContext. So now your views can call public methods (and properties) within your viewModel.
For significant things stick with DataBinding. otherwise, just call directly. Saves so much time and hassle.
I get the index for the pivotItem that I'm leaving, not the PivotItem that I'm going to! .
Using this:
<controls:Pivot x:Name="pivMain" Title="{Binding AppName}" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectServiceCommand}"
CommandParameter="{Binding ElementName=pivMain, Path=SelectedIndex}"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>

WPF ComboBox How to bind the selected item in code?

I have a combo box which is populated on selection's from two other combo'.
No problem I have this working.
Problem is I only want to activate the Selected Item binding after this has happened.
Here is my combo
<cuc:ComboBox Name="GopLenTypeCombo" Width="240" Height="24"
IsSynchronizedWithCurrentItem="True"
SelectedValue="{Binding Mode=TwoWay, Source={StaticResource ProfileDataProvider}, XPath=GopLenType}"
IsEnabled="False"/>
How do I stop the SelectedValue binding working untill I have populated the combo ?
I don't know whether this is possible in pure XAML, but if you have an underlying ViewModel, this wouldn't be too hard:
What you would need to do is to bind your third ComboBox to a property on the ViewModel (let's call this property Combo3Items).
You would also need to bind the two first ComboBoxes to properties on the same ViewModel (let's call these Combo1Items and Combo2Items, respectively). In addition to that, you could bind both of these ComboBoxes' SelectedValue to properties on the ViewModel, so that the ViewModel knows which items are selected.
Initially, Combo3Items would be empty, but as soon as the two bound SelectedValues are properly assigned, you can fill Combo3Items and raise an INotifyPropertyChanged event.
The MVVM architecture is very powerful. If you don't already know it, you can read more about it here.

Categories