Reputation: 377
I have a simple ListView in my View:
<ListView x:Name="ObjectListView" HorizontalAlignment="Left" Height="105" Margin="253,268,0,0" VerticalAlignment="Top" Width="163" SelectionChanged="ObjectListView_SelectionChanged">
<TextBox Width="100"/>
<Button Width="100" Content="Test"/>
<Label Width="100" Content="Label"/>
</ListView>
In my ViewModel, I have an ObservableCollection, which does a few (to this question irrelevant) things:
public ObservableCollection<Object> ObjectCollection
{
get { return _conversionCollection; }
set
{
if (_conversionCollection != value)
{
_conversionCollection = value;
RaisePropertyChanged("ObjectList");
}
}
}
Ultimatively, those Objects naturally land in the Model(edit: through the help of the RaisePropertyChanged and a few functions), but my problem here is the connection between View and ViewModel.
Currently, I have solved it like this (In the View's code-behind):
public MainWindow()
{
InitializeComponent();
_viewModel = (RibbonViewModel)base.DataContext;
}
private void ObjectListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_viewModel.ObjectCollection.Clear();
foreach(Object item in ObjectListView.SelectedItems)
{
_viewModel.ObjectCollection.Add(item);
}
}
This isn't all too beautiful, so I'd like to do it properly.
Upvotes: 0
Views: 1669
Reputation: 9827
<ListView x:Name="Lst" SelectedItem="{Binding ChosenItem}"> ... </ListView>
This will bring chosen item in the ChosenItem DP
, in its setter you can simply add the item to the collection.
private static void ChosenItemPropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
controls.Add(e.NewValue.ToString());
}
Upvotes: -1
Reputation: 27360
Basicaly, you need to databind ViewModel.ObjectCollection
to ListView.SelectedItems
.
WPF controls does not support this by default, however you could extend the control to support this feaure. One way of extending controls is behaviors. There are two types of behaviors:
Behaviors implemented as attached property.
<ListView my:ListViewExtension.SelectedItems="{Binding ObjectCollection}" />
I've decided to use second. Basically you create custom attached property and in DependencyPropertyChanged callback you can "inject" any code to the framework element by attaching to the element' eventhandlers.
public static class ListViewExtentions
{
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.RegisterAttached(
"SelectedItems", typeof (IList), typeof (ListViewExtentions), new PropertyMetadata(SelectedItems_PropertyChanged));
public static void SetSelectedItems(DependencyObject element, IList value)
{
element.SetValue(SelectedItemsProperty, value);
}
public static IList GetSelectedItems(DependencyObject element)
{
return (IList)element.GetValue(SelectedItemsProperty);
}
private static void SelectedItems_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listView = (ListView) d;
SynchronizeCollections(listView.SelectedItems, (IList)e.NewValue);
listView.SelectionChanged += (sender, args) =>
{
var listviewSelectedItems = ((ListView) sender).SelectedItems;
var viewmodelCollection = GetSelectedItems((ListView) sender);
SynchronizeCollections(listviewSelectedItems, viewmodelCollection);
};
}
private static void SynchronizeCollections(IList source, IList target)
{
var oldItems = target.OfType<object>().Except(source.OfType<object>()).ToArray();
var newItems = source.OfType<object>().Except(target.OfType<object>()).ToArray();
foreach (var oldItem in oldItems) target.Remove(oldItem);
foreach (var newItem in newItems) target.Add(newItem);
}
}
you can use propa
code snippet to generate attached property
TIP: I recommend you to rename ViewModel.ObjectCollection
to ViewModel.SelectedItems
, because now it is misleading.
Upvotes: 1
Reputation: 5474
You just need to bind your ListView
SelectedItems
to your ObservableCollection
, and thus your collection will be updated automatically using the binding. Actually you don't need to add he event to your code behind.
<ListView x:Name="ObjectListView" HorizontalAlignment="Left" Height="105" Margin="253,268,0,0" VerticalAlignment="Top" Width="163" SelectedItems="{Binding Path=ObjectCollection}">
<TextBox Width="100"/>
<Button Width="100" Content="Test"/>
<Label Width="100" Content="Label"/>
</ListView>
To achieve what you want try to use Interaction triggers
as below
Add below xmlns to your xaml
xmlns:i="http://schemas.microsoft.com/expression//2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Don't forget to add that reference :
Microsoft.Expression.Interactions System.Windows.Interactivity
<ListView x:Name="ObjectListView" HorizontalAlignment="Left" Height="105" Margin="253,268,0,0" VerticalAlignment="Top" Width="163">
<TextBox Width="100"/>
<Button Width="100" Content="Test"/>
<Label Width="100" Content="Label"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedItems" Value="{Binding Path=SelectedItems, ElementName=ObjectListView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
public System.Collections.IList SelectedItems {
get {
return ObjectCollection;
}
set {
ObjectCollection.Clear();
foreach (var model in value) {
ObjectCollection.Add(model);
}
}
}
Upvotes: 3
Reputation: 3462
Maybe this example will help you.
<Grid>
<ListView HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding ObjectCollection}" SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Width="100" Grid.Column="0" Text="{Binding Text}"/>
<Button Width="100" Content="Test" Grid.Column="1"/>
<Label Width="100" Grid.Column="2" Content="{Binding Label}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Code:
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class Obj : INotifyPropertyChanged
{
public string Text { get; set; }
private string label;
public string Label
{
get
{
return this.label;
}
set
{
this.label = value;
this.RaisePropertyChaged("Label");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChaged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
public class ViewModel
{
private Obj selectedItem;
public Obj SelectedItem
{
get
{
return this.selectedItem;
}
set
{
this.selectedItem = value;
this.selectedItem.Label = value.Text;
}
}
public ObservableCollection<Obj> ObjectCollection { get; set; }
public ViewModel()
{
ObjectCollection = new ObservableCollection<Obj>();
ObjectCollection.Add(new Obj { Text = "First" });
ObjectCollection.Add(new Obj { Text = "Second" });
ObjectCollection.Add(new Obj { Text = "Third" });
}
}
}
Upvotes: 0