Selecting multiple records in DataGrid with Caliburn.Micro
I have a WPF application using Caliburn.Micro.
The DataGrid has an attribute SelectedItem="{Binding Path=SelectedUsageRecord}"
As you can see, SelectedItem is bound to SelectedUsageRecord property. But I need to be able to handle selecting multiple records. Is this possible to bind multiple records to a collection property? I don't see anything like "SelectedItems"...
Thanks.
wpf caliburn.micro
add a comment |
I have a WPF application using Caliburn.Micro.
The DataGrid has an attribute SelectedItem="{Binding Path=SelectedUsageRecord}"
As you can see, SelectedItem is bound to SelectedUsageRecord property. But I need to be able to handle selecting multiple records. Is this possible to bind multiple records to a collection property? I don't see anything like "SelectedItems"...
Thanks.
wpf caliburn.micro
1
What DataGrid are you using? I know that with the telerik DataGrid you can do ContainerBindings so IsSelected can be bound to a Customer in the Customers collection. From there it's easy to find the selected items.
– Derek Beattie
Jun 4 '12 at 22:17
add a comment |
I have a WPF application using Caliburn.Micro.
The DataGrid has an attribute SelectedItem="{Binding Path=SelectedUsageRecord}"
As you can see, SelectedItem is bound to SelectedUsageRecord property. But I need to be able to handle selecting multiple records. Is this possible to bind multiple records to a collection property? I don't see anything like "SelectedItems"...
Thanks.
wpf caliburn.micro
I have a WPF application using Caliburn.Micro.
The DataGrid has an attribute SelectedItem="{Binding Path=SelectedUsageRecord}"
As you can see, SelectedItem is bound to SelectedUsageRecord property. But I need to be able to handle selecting multiple records. Is this possible to bind multiple records to a collection property? I don't see anything like "SelectedItems"...
Thanks.
wpf caliburn.micro
wpf caliburn.micro
asked May 23 '12 at 14:14
David ShochetDavid Shochet
1,865102959
1,865102959
1
What DataGrid are you using? I know that with the telerik DataGrid you can do ContainerBindings so IsSelected can be bound to a Customer in the Customers collection. From there it's easy to find the selected items.
– Derek Beattie
Jun 4 '12 at 22:17
add a comment |
1
What DataGrid are you using? I know that with the telerik DataGrid you can do ContainerBindings so IsSelected can be bound to a Customer in the Customers collection. From there it's easy to find the selected items.
– Derek Beattie
Jun 4 '12 at 22:17
1
1
What DataGrid are you using? I know that with the telerik DataGrid you can do ContainerBindings so IsSelected can be bound to a Customer in the Customers collection. From there it's easy to find the selected items.
– Derek Beattie
Jun 4 '12 at 22:17
What DataGrid are you using? I know that with the telerik DataGrid you can do ContainerBindings so IsSelected can be bound to a Customer in the Customers collection. From there it's easy to find the selected items.
– Derek Beattie
Jun 4 '12 at 22:17
add a comment |
3 Answers
3
active
oldest
votes
Here's what I did after striking the same scenario as you. In short handle the selection change event directly and pull the selected rows from the event args.
Assuming a source collection of "Rows" each one being a RowViewModel, and a collection for the "_selectedRows".
<DataGrid RowsSource="{Binding Rows}" x:Name="Rows"
SelectionMode="Extended" SelectionUnit="FullRow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cal:ActionMessage MethodName="SelectedRowsChangeEvent">
<cal:Parameter Value="$eventArgs" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
public void SelectedRowsChangeEvent(SelectionChangedEventArgs e)
{
foreach (var addedRow in e.AddedRows)
{
_selectedRows.Add(addedRow as RowViewModel);
}
foreach (var removedRow in e.RemovedRows)
{
_selectedRows.Remove(removedRow as RowViewModel);
}
}
add a comment |
I just wanted to post my solution. In Caliburn micro there is no need to set the source as long as you stay true to the naming convention.
Xaml
<DataGrid x:Name="Rows" SelectionMode="Extended" cal:Message.Attach="[Event SelectionChanged] = [Row_SelectionChanged($eventArgs)]">
C#
public List<MyObject> Rows { get; set; }
public MyObject SelectedRow { get; set; } //Will be set by Caliburn Micro. No need to use "SelectedItem={...}"
List<MyObject> _selectedObjects = new List<MyObject>();
public void Row_SelectionChanged(SelectionChangedEventArgs obj)
{
_selectedObjects.AddRange(obj.AddedItems.Cast<MyObject>());
obj.RemovedItems.Cast<MyObject>().ToList().ForEach(w => _selectedObjects.Remove(w));
}
add a comment |
Both solutions posted here work fine but they rely on adding a view (wpf) assembly in your viewmodel because of the "SelectionChangedEventArgs" property. This, i think, is not good for cross platform solutions in case you intend to reuse the viewmodels in different platforms.
So, i'm posting my solution that it's more in line with the MVVM pattern. I'm using syncfusion SfDataGrid in this example but this should work fine with a normal DataGrid:
First we need to extend the DataGrid class, so we create a class. I named it "CustomSfDataGrid.cs". Note that i'm also subscribing to the SelectionChanged event and just obtaining the data directly from the "SelectedItems" property.
using System.Windows;
using Caliburn.Micro;
using Syncfusion.UI.Xaml.Grid;
namespace DesktopClient.WPF.Controls
{
public class CustomSfDataGrid : SfDataGrid
{
///Bindable collection of objects property linked to the DependencyProperty called: "CustomSelectedItems"
///We can use "CustomSelectedItems" as a Binding Property in WPF
public BindableCollection<object> CustomSelectedItems
{
get
{
return (BindableCollection<object>)GetValue(CustomSelectedItemsProperty);
}
set
{
SetValue(CustomSelectedItemsProperty, value);
}
}
// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomSelectedItemsProperty = DependencyProperty.Register("CustomSelectedItems", typeof(BindableCollection<object>), typeof(CustomSfDataGrid), new PropertyMetadata(null));
public CustomSfDataGrid()
{
SelectionChanged += CustomSfDataGrid_SelectionChanged;
}
private void CustomSfDataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
this.CustomSelectedItems = new BindableCollection<object>(this.SelectedItems);
}
}
}
In the .xaml file i added a header called "custom" that is pointing to the namespace of my "CustomSfDataGrid.cs". Then, i'm binding the new "CustomSelectedItems" property to "MyViewModelProperty". Finally, i'm using the "SelectionChanged" event.
<UserControl
xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
xmlns:cal="http://www.caliburnproject.org"
xmlns:custom="clr-namespace:DesktopClient.WPF.Controls">
<Grid>
<custom:CustomSfDataGrid x:Name="dataGrid" ItemsSource="{Binding Models}"
SelectionMode="Extended" SelectionChanged="OnSelectionChanged"
CustomSelectedItems="{Binding MyViewModelProperty, Mode=OneWayToSource}">
<syncfusion:SfDataGrid.Columns>
<!-- Column Schema -->
</syncfusion:SfDataGrid.Columns>
</custom:CustomSfDataGrid>
</Grid>
Finally, in the ViewModel i have a "BindableCollection" property.
using using System.Linq;
//
//...
private BindableCollection<object> _myViewModelProperty;
public BindableCollection<object> MyViewModelProperty
{
get
{
return _myViewModelProperty;
}
set
{
_myViewModelProperty = value;
}
}
//
public void UsingMyViewModel()
{
//cast the collection of objects to a different type using linq
BindableCollection<MyCastedType> x = new BindableCollection<BrandModel>(MyViewModelProperty.OfType<BrandModel>());
//alternative casting method
BindableCollection<MyCastedType> y = new BindableCollection<MyCastedType>();
foreach (var item in MyViewModelProperty)
{
y.Add(item as MyCastedType);
}
}
Ok... so apparently just binding the "SelectedItems" xaml property to a ObservableCollection<objects> property in the viewmodel works fine. No need to extend the class. I'm keeping my original post just in case someone still finds it useful.
– Dev Kevin
Nov 20 '18 at 5:08
Hi Im currently using your approach in my app and it works perfect with an standard datagrid, the only problem is when I try to update the selected items from viewmodel it dont works. Is there any solution for this. Note: binding directly SelectedItems to an ObservableCollection dont work in an standard datagrid.
– Alexei Agüero Alba
Jan 25 at 12:55
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f10721794%2fselecting-multiple-records-in-datagrid-with-caliburn-micro%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Here's what I did after striking the same scenario as you. In short handle the selection change event directly and pull the selected rows from the event args.
Assuming a source collection of "Rows" each one being a RowViewModel, and a collection for the "_selectedRows".
<DataGrid RowsSource="{Binding Rows}" x:Name="Rows"
SelectionMode="Extended" SelectionUnit="FullRow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cal:ActionMessage MethodName="SelectedRowsChangeEvent">
<cal:Parameter Value="$eventArgs" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
public void SelectedRowsChangeEvent(SelectionChangedEventArgs e)
{
foreach (var addedRow in e.AddedRows)
{
_selectedRows.Add(addedRow as RowViewModel);
}
foreach (var removedRow in e.RemovedRows)
{
_selectedRows.Remove(removedRow as RowViewModel);
}
}
add a comment |
Here's what I did after striking the same scenario as you. In short handle the selection change event directly and pull the selected rows from the event args.
Assuming a source collection of "Rows" each one being a RowViewModel, and a collection for the "_selectedRows".
<DataGrid RowsSource="{Binding Rows}" x:Name="Rows"
SelectionMode="Extended" SelectionUnit="FullRow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cal:ActionMessage MethodName="SelectedRowsChangeEvent">
<cal:Parameter Value="$eventArgs" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
public void SelectedRowsChangeEvent(SelectionChangedEventArgs e)
{
foreach (var addedRow in e.AddedRows)
{
_selectedRows.Add(addedRow as RowViewModel);
}
foreach (var removedRow in e.RemovedRows)
{
_selectedRows.Remove(removedRow as RowViewModel);
}
}
add a comment |
Here's what I did after striking the same scenario as you. In short handle the selection change event directly and pull the selected rows from the event args.
Assuming a source collection of "Rows" each one being a RowViewModel, and a collection for the "_selectedRows".
<DataGrid RowsSource="{Binding Rows}" x:Name="Rows"
SelectionMode="Extended" SelectionUnit="FullRow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cal:ActionMessage MethodName="SelectedRowsChangeEvent">
<cal:Parameter Value="$eventArgs" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
public void SelectedRowsChangeEvent(SelectionChangedEventArgs e)
{
foreach (var addedRow in e.AddedRows)
{
_selectedRows.Add(addedRow as RowViewModel);
}
foreach (var removedRow in e.RemovedRows)
{
_selectedRows.Remove(removedRow as RowViewModel);
}
}
Here's what I did after striking the same scenario as you. In short handle the selection change event directly and pull the selected rows from the event args.
Assuming a source collection of "Rows" each one being a RowViewModel, and a collection for the "_selectedRows".
<DataGrid RowsSource="{Binding Rows}" x:Name="Rows"
SelectionMode="Extended" SelectionUnit="FullRow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cal:ActionMessage MethodName="SelectedRowsChangeEvent">
<cal:Parameter Value="$eventArgs" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
public void SelectedRowsChangeEvent(SelectionChangedEventArgs e)
{
foreach (var addedRow in e.AddedRows)
{
_selectedRows.Add(addedRow as RowViewModel);
}
foreach (var removedRow in e.RemovedRows)
{
_selectedRows.Remove(removedRow as RowViewModel);
}
}
answered Nov 1 '12 at 2:04
DaveDave
7612
7612
add a comment |
add a comment |
I just wanted to post my solution. In Caliburn micro there is no need to set the source as long as you stay true to the naming convention.
Xaml
<DataGrid x:Name="Rows" SelectionMode="Extended" cal:Message.Attach="[Event SelectionChanged] = [Row_SelectionChanged($eventArgs)]">
C#
public List<MyObject> Rows { get; set; }
public MyObject SelectedRow { get; set; } //Will be set by Caliburn Micro. No need to use "SelectedItem={...}"
List<MyObject> _selectedObjects = new List<MyObject>();
public void Row_SelectionChanged(SelectionChangedEventArgs obj)
{
_selectedObjects.AddRange(obj.AddedItems.Cast<MyObject>());
obj.RemovedItems.Cast<MyObject>().ToList().ForEach(w => _selectedObjects.Remove(w));
}
add a comment |
I just wanted to post my solution. In Caliburn micro there is no need to set the source as long as you stay true to the naming convention.
Xaml
<DataGrid x:Name="Rows" SelectionMode="Extended" cal:Message.Attach="[Event SelectionChanged] = [Row_SelectionChanged($eventArgs)]">
C#
public List<MyObject> Rows { get; set; }
public MyObject SelectedRow { get; set; } //Will be set by Caliburn Micro. No need to use "SelectedItem={...}"
List<MyObject> _selectedObjects = new List<MyObject>();
public void Row_SelectionChanged(SelectionChangedEventArgs obj)
{
_selectedObjects.AddRange(obj.AddedItems.Cast<MyObject>());
obj.RemovedItems.Cast<MyObject>().ToList().ForEach(w => _selectedObjects.Remove(w));
}
add a comment |
I just wanted to post my solution. In Caliburn micro there is no need to set the source as long as you stay true to the naming convention.
Xaml
<DataGrid x:Name="Rows" SelectionMode="Extended" cal:Message.Attach="[Event SelectionChanged] = [Row_SelectionChanged($eventArgs)]">
C#
public List<MyObject> Rows { get; set; }
public MyObject SelectedRow { get; set; } //Will be set by Caliburn Micro. No need to use "SelectedItem={...}"
List<MyObject> _selectedObjects = new List<MyObject>();
public void Row_SelectionChanged(SelectionChangedEventArgs obj)
{
_selectedObjects.AddRange(obj.AddedItems.Cast<MyObject>());
obj.RemovedItems.Cast<MyObject>().ToList().ForEach(w => _selectedObjects.Remove(w));
}
I just wanted to post my solution. In Caliburn micro there is no need to set the source as long as you stay true to the naming convention.
Xaml
<DataGrid x:Name="Rows" SelectionMode="Extended" cal:Message.Attach="[Event SelectionChanged] = [Row_SelectionChanged($eventArgs)]">
C#
public List<MyObject> Rows { get; set; }
public MyObject SelectedRow { get; set; } //Will be set by Caliburn Micro. No need to use "SelectedItem={...}"
List<MyObject> _selectedObjects = new List<MyObject>();
public void Row_SelectionChanged(SelectionChangedEventArgs obj)
{
_selectedObjects.AddRange(obj.AddedItems.Cast<MyObject>());
obj.RemovedItems.Cast<MyObject>().ToList().ForEach(w => _selectedObjects.Remove(w));
}
answered Jan 10 '17 at 7:24
RahbekRahbek
70185
70185
add a comment |
add a comment |
Both solutions posted here work fine but they rely on adding a view (wpf) assembly in your viewmodel because of the "SelectionChangedEventArgs" property. This, i think, is not good for cross platform solutions in case you intend to reuse the viewmodels in different platforms.
So, i'm posting my solution that it's more in line with the MVVM pattern. I'm using syncfusion SfDataGrid in this example but this should work fine with a normal DataGrid:
First we need to extend the DataGrid class, so we create a class. I named it "CustomSfDataGrid.cs". Note that i'm also subscribing to the SelectionChanged event and just obtaining the data directly from the "SelectedItems" property.
using System.Windows;
using Caliburn.Micro;
using Syncfusion.UI.Xaml.Grid;
namespace DesktopClient.WPF.Controls
{
public class CustomSfDataGrid : SfDataGrid
{
///Bindable collection of objects property linked to the DependencyProperty called: "CustomSelectedItems"
///We can use "CustomSelectedItems" as a Binding Property in WPF
public BindableCollection<object> CustomSelectedItems
{
get
{
return (BindableCollection<object>)GetValue(CustomSelectedItemsProperty);
}
set
{
SetValue(CustomSelectedItemsProperty, value);
}
}
// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomSelectedItemsProperty = DependencyProperty.Register("CustomSelectedItems", typeof(BindableCollection<object>), typeof(CustomSfDataGrid), new PropertyMetadata(null));
public CustomSfDataGrid()
{
SelectionChanged += CustomSfDataGrid_SelectionChanged;
}
private void CustomSfDataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
this.CustomSelectedItems = new BindableCollection<object>(this.SelectedItems);
}
}
}
In the .xaml file i added a header called "custom" that is pointing to the namespace of my "CustomSfDataGrid.cs". Then, i'm binding the new "CustomSelectedItems" property to "MyViewModelProperty". Finally, i'm using the "SelectionChanged" event.
<UserControl
xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
xmlns:cal="http://www.caliburnproject.org"
xmlns:custom="clr-namespace:DesktopClient.WPF.Controls">
<Grid>
<custom:CustomSfDataGrid x:Name="dataGrid" ItemsSource="{Binding Models}"
SelectionMode="Extended" SelectionChanged="OnSelectionChanged"
CustomSelectedItems="{Binding MyViewModelProperty, Mode=OneWayToSource}">
<syncfusion:SfDataGrid.Columns>
<!-- Column Schema -->
</syncfusion:SfDataGrid.Columns>
</custom:CustomSfDataGrid>
</Grid>
Finally, in the ViewModel i have a "BindableCollection" property.
using using System.Linq;
//
//...
private BindableCollection<object> _myViewModelProperty;
public BindableCollection<object> MyViewModelProperty
{
get
{
return _myViewModelProperty;
}
set
{
_myViewModelProperty = value;
}
}
//
public void UsingMyViewModel()
{
//cast the collection of objects to a different type using linq
BindableCollection<MyCastedType> x = new BindableCollection<BrandModel>(MyViewModelProperty.OfType<BrandModel>());
//alternative casting method
BindableCollection<MyCastedType> y = new BindableCollection<MyCastedType>();
foreach (var item in MyViewModelProperty)
{
y.Add(item as MyCastedType);
}
}
Ok... so apparently just binding the "SelectedItems" xaml property to a ObservableCollection<objects> property in the viewmodel works fine. No need to extend the class. I'm keeping my original post just in case someone still finds it useful.
– Dev Kevin
Nov 20 '18 at 5:08
Hi Im currently using your approach in my app and it works perfect with an standard datagrid, the only problem is when I try to update the selected items from viewmodel it dont works. Is there any solution for this. Note: binding directly SelectedItems to an ObservableCollection dont work in an standard datagrid.
– Alexei Agüero Alba
Jan 25 at 12:55
add a comment |
Both solutions posted here work fine but they rely on adding a view (wpf) assembly in your viewmodel because of the "SelectionChangedEventArgs" property. This, i think, is not good for cross platform solutions in case you intend to reuse the viewmodels in different platforms.
So, i'm posting my solution that it's more in line with the MVVM pattern. I'm using syncfusion SfDataGrid in this example but this should work fine with a normal DataGrid:
First we need to extend the DataGrid class, so we create a class. I named it "CustomSfDataGrid.cs". Note that i'm also subscribing to the SelectionChanged event and just obtaining the data directly from the "SelectedItems" property.
using System.Windows;
using Caliburn.Micro;
using Syncfusion.UI.Xaml.Grid;
namespace DesktopClient.WPF.Controls
{
public class CustomSfDataGrid : SfDataGrid
{
///Bindable collection of objects property linked to the DependencyProperty called: "CustomSelectedItems"
///We can use "CustomSelectedItems" as a Binding Property in WPF
public BindableCollection<object> CustomSelectedItems
{
get
{
return (BindableCollection<object>)GetValue(CustomSelectedItemsProperty);
}
set
{
SetValue(CustomSelectedItemsProperty, value);
}
}
// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomSelectedItemsProperty = DependencyProperty.Register("CustomSelectedItems", typeof(BindableCollection<object>), typeof(CustomSfDataGrid), new PropertyMetadata(null));
public CustomSfDataGrid()
{
SelectionChanged += CustomSfDataGrid_SelectionChanged;
}
private void CustomSfDataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
this.CustomSelectedItems = new BindableCollection<object>(this.SelectedItems);
}
}
}
In the .xaml file i added a header called "custom" that is pointing to the namespace of my "CustomSfDataGrid.cs". Then, i'm binding the new "CustomSelectedItems" property to "MyViewModelProperty". Finally, i'm using the "SelectionChanged" event.
<UserControl
xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
xmlns:cal="http://www.caliburnproject.org"
xmlns:custom="clr-namespace:DesktopClient.WPF.Controls">
<Grid>
<custom:CustomSfDataGrid x:Name="dataGrid" ItemsSource="{Binding Models}"
SelectionMode="Extended" SelectionChanged="OnSelectionChanged"
CustomSelectedItems="{Binding MyViewModelProperty, Mode=OneWayToSource}">
<syncfusion:SfDataGrid.Columns>
<!-- Column Schema -->
</syncfusion:SfDataGrid.Columns>
</custom:CustomSfDataGrid>
</Grid>
Finally, in the ViewModel i have a "BindableCollection" property.
using using System.Linq;
//
//...
private BindableCollection<object> _myViewModelProperty;
public BindableCollection<object> MyViewModelProperty
{
get
{
return _myViewModelProperty;
}
set
{
_myViewModelProperty = value;
}
}
//
public void UsingMyViewModel()
{
//cast the collection of objects to a different type using linq
BindableCollection<MyCastedType> x = new BindableCollection<BrandModel>(MyViewModelProperty.OfType<BrandModel>());
//alternative casting method
BindableCollection<MyCastedType> y = new BindableCollection<MyCastedType>();
foreach (var item in MyViewModelProperty)
{
y.Add(item as MyCastedType);
}
}
Ok... so apparently just binding the "SelectedItems" xaml property to a ObservableCollection<objects> property in the viewmodel works fine. No need to extend the class. I'm keeping my original post just in case someone still finds it useful.
– Dev Kevin
Nov 20 '18 at 5:08
Hi Im currently using your approach in my app and it works perfect with an standard datagrid, the only problem is when I try to update the selected items from viewmodel it dont works. Is there any solution for this. Note: binding directly SelectedItems to an ObservableCollection dont work in an standard datagrid.
– Alexei Agüero Alba
Jan 25 at 12:55
add a comment |
Both solutions posted here work fine but they rely on adding a view (wpf) assembly in your viewmodel because of the "SelectionChangedEventArgs" property. This, i think, is not good for cross platform solutions in case you intend to reuse the viewmodels in different platforms.
So, i'm posting my solution that it's more in line with the MVVM pattern. I'm using syncfusion SfDataGrid in this example but this should work fine with a normal DataGrid:
First we need to extend the DataGrid class, so we create a class. I named it "CustomSfDataGrid.cs". Note that i'm also subscribing to the SelectionChanged event and just obtaining the data directly from the "SelectedItems" property.
using System.Windows;
using Caliburn.Micro;
using Syncfusion.UI.Xaml.Grid;
namespace DesktopClient.WPF.Controls
{
public class CustomSfDataGrid : SfDataGrid
{
///Bindable collection of objects property linked to the DependencyProperty called: "CustomSelectedItems"
///We can use "CustomSelectedItems" as a Binding Property in WPF
public BindableCollection<object> CustomSelectedItems
{
get
{
return (BindableCollection<object>)GetValue(CustomSelectedItemsProperty);
}
set
{
SetValue(CustomSelectedItemsProperty, value);
}
}
// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomSelectedItemsProperty = DependencyProperty.Register("CustomSelectedItems", typeof(BindableCollection<object>), typeof(CustomSfDataGrid), new PropertyMetadata(null));
public CustomSfDataGrid()
{
SelectionChanged += CustomSfDataGrid_SelectionChanged;
}
private void CustomSfDataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
this.CustomSelectedItems = new BindableCollection<object>(this.SelectedItems);
}
}
}
In the .xaml file i added a header called "custom" that is pointing to the namespace of my "CustomSfDataGrid.cs". Then, i'm binding the new "CustomSelectedItems" property to "MyViewModelProperty". Finally, i'm using the "SelectionChanged" event.
<UserControl
xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
xmlns:cal="http://www.caliburnproject.org"
xmlns:custom="clr-namespace:DesktopClient.WPF.Controls">
<Grid>
<custom:CustomSfDataGrid x:Name="dataGrid" ItemsSource="{Binding Models}"
SelectionMode="Extended" SelectionChanged="OnSelectionChanged"
CustomSelectedItems="{Binding MyViewModelProperty, Mode=OneWayToSource}">
<syncfusion:SfDataGrid.Columns>
<!-- Column Schema -->
</syncfusion:SfDataGrid.Columns>
</custom:CustomSfDataGrid>
</Grid>
Finally, in the ViewModel i have a "BindableCollection" property.
using using System.Linq;
//
//...
private BindableCollection<object> _myViewModelProperty;
public BindableCollection<object> MyViewModelProperty
{
get
{
return _myViewModelProperty;
}
set
{
_myViewModelProperty = value;
}
}
//
public void UsingMyViewModel()
{
//cast the collection of objects to a different type using linq
BindableCollection<MyCastedType> x = new BindableCollection<BrandModel>(MyViewModelProperty.OfType<BrandModel>());
//alternative casting method
BindableCollection<MyCastedType> y = new BindableCollection<MyCastedType>();
foreach (var item in MyViewModelProperty)
{
y.Add(item as MyCastedType);
}
}
Both solutions posted here work fine but they rely on adding a view (wpf) assembly in your viewmodel because of the "SelectionChangedEventArgs" property. This, i think, is not good for cross platform solutions in case you intend to reuse the viewmodels in different platforms.
So, i'm posting my solution that it's more in line with the MVVM pattern. I'm using syncfusion SfDataGrid in this example but this should work fine with a normal DataGrid:
First we need to extend the DataGrid class, so we create a class. I named it "CustomSfDataGrid.cs". Note that i'm also subscribing to the SelectionChanged event and just obtaining the data directly from the "SelectedItems" property.
using System.Windows;
using Caliburn.Micro;
using Syncfusion.UI.Xaml.Grid;
namespace DesktopClient.WPF.Controls
{
public class CustomSfDataGrid : SfDataGrid
{
///Bindable collection of objects property linked to the DependencyProperty called: "CustomSelectedItems"
///We can use "CustomSelectedItems" as a Binding Property in WPF
public BindableCollection<object> CustomSelectedItems
{
get
{
return (BindableCollection<object>)GetValue(CustomSelectedItemsProperty);
}
set
{
SetValue(CustomSelectedItemsProperty, value);
}
}
// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomSelectedItemsProperty = DependencyProperty.Register("CustomSelectedItems", typeof(BindableCollection<object>), typeof(CustomSfDataGrid), new PropertyMetadata(null));
public CustomSfDataGrid()
{
SelectionChanged += CustomSfDataGrid_SelectionChanged;
}
private void CustomSfDataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
this.CustomSelectedItems = new BindableCollection<object>(this.SelectedItems);
}
}
}
In the .xaml file i added a header called "custom" that is pointing to the namespace of my "CustomSfDataGrid.cs". Then, i'm binding the new "CustomSelectedItems" property to "MyViewModelProperty". Finally, i'm using the "SelectionChanged" event.
<UserControl
xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
xmlns:cal="http://www.caliburnproject.org"
xmlns:custom="clr-namespace:DesktopClient.WPF.Controls">
<Grid>
<custom:CustomSfDataGrid x:Name="dataGrid" ItemsSource="{Binding Models}"
SelectionMode="Extended" SelectionChanged="OnSelectionChanged"
CustomSelectedItems="{Binding MyViewModelProperty, Mode=OneWayToSource}">
<syncfusion:SfDataGrid.Columns>
<!-- Column Schema -->
</syncfusion:SfDataGrid.Columns>
</custom:CustomSfDataGrid>
</Grid>
Finally, in the ViewModel i have a "BindableCollection" property.
using using System.Linq;
//
//...
private BindableCollection<object> _myViewModelProperty;
public BindableCollection<object> MyViewModelProperty
{
get
{
return _myViewModelProperty;
}
set
{
_myViewModelProperty = value;
}
}
//
public void UsingMyViewModel()
{
//cast the collection of objects to a different type using linq
BindableCollection<MyCastedType> x = new BindableCollection<BrandModel>(MyViewModelProperty.OfType<BrandModel>());
//alternative casting method
BindableCollection<MyCastedType> y = new BindableCollection<MyCastedType>();
foreach (var item in MyViewModelProperty)
{
y.Add(item as MyCastedType);
}
}
edited Nov 20 '18 at 4:59
answered Nov 20 '18 at 4:30
Dev KevinDev Kevin
412
412
Ok... so apparently just binding the "SelectedItems" xaml property to a ObservableCollection<objects> property in the viewmodel works fine. No need to extend the class. I'm keeping my original post just in case someone still finds it useful.
– Dev Kevin
Nov 20 '18 at 5:08
Hi Im currently using your approach in my app and it works perfect with an standard datagrid, the only problem is when I try to update the selected items from viewmodel it dont works. Is there any solution for this. Note: binding directly SelectedItems to an ObservableCollection dont work in an standard datagrid.
– Alexei Agüero Alba
Jan 25 at 12:55
add a comment |
Ok... so apparently just binding the "SelectedItems" xaml property to a ObservableCollection<objects> property in the viewmodel works fine. No need to extend the class. I'm keeping my original post just in case someone still finds it useful.
– Dev Kevin
Nov 20 '18 at 5:08
Hi Im currently using your approach in my app and it works perfect with an standard datagrid, the only problem is when I try to update the selected items from viewmodel it dont works. Is there any solution for this. Note: binding directly SelectedItems to an ObservableCollection dont work in an standard datagrid.
– Alexei Agüero Alba
Jan 25 at 12:55
Ok... so apparently just binding the "SelectedItems" xaml property to a ObservableCollection<objects> property in the viewmodel works fine. No need to extend the class. I'm keeping my original post just in case someone still finds it useful.
– Dev Kevin
Nov 20 '18 at 5:08
Ok... so apparently just binding the "SelectedItems" xaml property to a ObservableCollection<objects> property in the viewmodel works fine. No need to extend the class. I'm keeping my original post just in case someone still finds it useful.
– Dev Kevin
Nov 20 '18 at 5:08
Hi Im currently using your approach in my app and it works perfect with an standard datagrid, the only problem is when I try to update the selected items from viewmodel it dont works. Is there any solution for this. Note: binding directly SelectedItems to an ObservableCollection dont work in an standard datagrid.
– Alexei Agüero Alba
Jan 25 at 12:55
Hi Im currently using your approach in my app and it works perfect with an standard datagrid, the only problem is when I try to update the selected items from viewmodel it dont works. Is there any solution for this. Note: binding directly SelectedItems to an ObservableCollection dont work in an standard datagrid.
– Alexei Agüero Alba
Jan 25 at 12:55
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f10721794%2fselecting-multiple-records-in-datagrid-with-caliburn-micro%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
What DataGrid are you using? I know that with the telerik DataGrid you can do ContainerBindings so IsSelected can be bound to a Customer in the Customers collection. From there it's easy to find the selected items.
– Derek Beattie
Jun 4 '12 at 22:17