
I am currently implementing MVVM in my application, and I am working with a GridView. My gridview to bound to my "AllClasses" property (ObservableCollection of Class) of my view model. When I want to add a new row, I simply adda new class to my AllClasses property and the gridview automatically updates itself with a blank row.
However, my issue is that, even though the first cell of this blank row is highlighted, when i start typing the cell doesnt take what im inputting. I have to click on the cell first, then start typing and it takes the values im entering.
How can I make it so the cell is ready for input immediatly? It should be because the first cell of this blank row is highlighted already, and for any other cell in my grid, if i click on the cell (so its highlighted) and start typing, it records my input.
Thanks,
18 Answers, 1 is accepted
You may set the first cell in that particular one as the current one and focus the grid. Once you add the item, you may do something similar to the approach described in this article. In your case you can use only the following lines:
gridView.CurrentCellInfo = new GridViewCellInfo(gridView.Items[5], gridView.Columns["Text"]);
gridView.Focus();
However, if that does not meet your requirements, please provide a bit more details on your scenario. How do you add this new item - on a click event of a button or handling the AddingNewDataItem event ?
Regards,
Maya
the Telerik team

Thank you for your response.
I am purely using MVVM, so my ViewModel doesn't know anything about my grid. i am using commands to add rows. So when my add button is clicked, a command fires in my view model, and I add a new entity to my observable collection (which is the datasource for the grid) and by doing so, the grid is automatically refreshed with this new row.
Here is my XAML:
<
telerik:RadButton
Style
=
"{StaticResource AddButtonStyle}"
Command
=
"{Binding AddBlankClassCommand}"
>
<
StackPanel
Orientation
=
"Horizontal"
>
<
TextBlock
Foreground
=
"DarkBlue"
>New Class</
TextBlock
>
</
StackPanel
>
</
telerik:RadButton
>
<
telerik:RadGridView
x:Name
=
"dgClasses"
Grid.Row
=
"1"
AutoGenerateColumns
=
"False"
Style
=
"{StaticResource DataGridStyle}"
ItemsSource
=
"{Binding AllClasses}"
>
And here is my "AddBlankClassCommand":
public
void
AddBlankClass()
{
var classVM =
new
ClassViewModel()
classVM.ClassAddedOrRemoved += OnCollectionRefreshed;
classVM.NameChanged += OnClassNameChanged;
AllClasses.Insert(0, classVM);
}
When this code executes, the view (my data grid) is automatically refreshed to display a blank row, and even further, the first cell of this row is already highlighted! So when a user starts typing, you expect the cell to take the value, but it doesn't.
How do I really have this cell selected?
Thanks,
If you want to be able to start typing once a new item is added, you need to make sure that the grid has the focus and the cell you want to edit is the current one.
Maya
the Telerik team

as Dan was saying, with MVVM architecture business logic should not exist in UI. Therefore, if UI issues a command to add a row, ViewModel needs to bind to this command, get a new object from Model with initial data assigned, and then add this object to underlying collection.
At this point, RadGridView should detect that a new row is being added, and fire some event where we should be able to set the focus on a particular column within a new row, and possibly start editing the cell.
Is there such an event in RadGridView? AddingNewDataItem event is not being fired in this case, so we need another event
You can try working with the built-in commands. Please refer to our online documentation and demos for a reference.
Maya
the Telerik team


I have the same Problem like Dan.
I have a Command (residing in the ViewModel) for Adding a new DataEntity to a ObservableCollection in my ViewModel. Lets call the property hosting my ObservableCollection, DataEntities.
DataEntities is bound to the ItemsSource property of the RadGridView, showing the Entities.
I want my own Add-Command to be responsible for adding the Data. I don't want the UI to be responsible for that an hoping all the DataBinding stuff will work correctly and update my DataEntities property (if there is a UI at all... this is not the case in a UnitTest). I am not absolutely sure if Telerik UI-Commands work this way, but i assume they do. Am i right with that?
I still want my new Entity to be in EditMode after it was added, but i want a stronger separation between View and ViewModel than it would be when using your UI-Commands and wait for the Entities to be updated via DataBinding by the View. And i want to write Unit-/Integrations-Tests for this Command which should run without UI at all.
The only way i could imagine, is to write a Event-Handler (or UI-Command) in the View Layer, which uses my Add-Command from the ViewModel-Layer. After updating the ViewModel by ViewModel-Command, the EventHandler (or UI-Command) has to look for the new Entity and its relating DataRow and set it to EditMode. (here again, we have business logic in the View... but imo. not to much)
<Edit>
The above is not the only way i can imagine, this statement was wrong. Goran's suggested solution, using a Message, would work too. But like Goran, i would prefer solution which is more simple.
</Edit>
This seems still like a lot of work for a small Problem. Maybe there is a better solution.
How would you achieve this "stronger separation" and still get new rows to be added in EditMode?
Thank you in advance
Michael
If you want GridView to go into edit mode, you need to make sure that it has the focus. I am afraid that, you can not achieve the desired behaviour only by adding a new DataItem to your ObservableCollection.
As my colleague already mentioned, you can try working with the built-in commands.
Yoan
the Telerik team
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

one way you could do it is by writing some UI logic in your view that listen for CollectionChanged events
raised by the ObservableCollection exposed by your viewModel.
If e.Action is "Added", then focus the gridview (you are in the view here, so you can reference the gridview).
In other words: have the view take a dependency on your viewModel instead of the other way around,
so you can still unit-test without problems.
Be careful to properly unsubscribe the event whenever your ObservableCollection instance is replaced
in the viewModel (if applicable) or whenever the view's datacontext changes, so that you don't end up with memory leaks
or weird behaviors.
Here is my code:
note that in my case "Columns" is the name of the property used as ItemsSource (i.e. our ObservableCollection) from my ViewModel.
The name is because I'm designing a table editor so each row is in fact a column business-wise).
Also: "Length" is the UniqueName of the GridViewDataColumn that I want the edit to start from whenever I add a new row.
I found out that I needed to call BeginEdit() after Focus() to actually enter edit mode...
View.cs:
public
partial
class
FixedLengthSpecificationView : UserControl
{
//Used to hold the previous collection in order to correctly unsubscribe events
private
ObservableCollection<ColumnViewModel> _lastCollection;
public
FixedLengthSpecificationView()
{
InitializeComponent();
DataContextChanged += MyDataContextChanged;
}
private
void
MyDataContextChanged(
object
sender, DependencyPropertyChangedEventArgs e)
{
var vm = e.OldValue
as
FixedLengthSpecificationViewModel;
if
(vm !=
null
)
{
vm.PropertyChanged -= ViewModelPropertyChanged;
if
(_lastCollection !=
null
)
_lastCollection.CollectionChanged -= ColumnsCollectionChanged;
}
vm = e.NewValue
as
FixedLengthSpecificationViewModel;
if
(vm !=
null
)
{
vm.PropertyChanged += ViewModelPropertyChanged;
_lastCollection = vm.Columns;
if
(_lastCollection !=
null
)
_lastCollection.CollectionChanged += ColumnsCollectionChanged;
}
}
private
void
ColumnsCollectionChanged(
object
sender, NotifyCollectionChangedEventArgs e)
{
if
(e.Action == NotifyCollectionChangedAction.Add)
{
GridView.CurrentCellInfo =
new
GridViewCellInfo(e.NewItems[0], GridView.Columns[
"Length"
]);
GridView.Focus();
GridView.BeginEdit();
}
}
private
void
ViewModelPropertyChanged(
object
sender, PropertyChangedEventArgs e)
{
if
(e.PropertyName ==
"Columns"
)
{
if
(_lastCollection !=
null
)
_lastCollection.CollectionChanged -= ColumnsCollectionChanged;
_lastCollection = ((FixedLengthSpecificationViewModel) sender).Columns;
if
(_lastCollection !=
null
)
_lastCollection.CollectionChanged += ColumnsCollectionChanged;
}
}
}
Hope this helps :-)
-Rodrigo-

Hi
@Yoan: Thanks for your reply. I agree with that. But i don't understand how "the built-in commands." could help me in my situation. As far as i understand, they reside very close to the view (RadGridView). They need a RadGridView-Instance to be executed. My desire is to have commands which can be executed without a view. So they can be unit-tested easy.
@Rodro: Thanks, i am pretty sure, that will do the job! I will try that.
Thank you all
Michael
I might be missing something here, but as far as I get you want to be able to add a new item into your collection directly and once you do that, to be able to start typing. Am I right ?
If that is the case, you need to make sure that the grid has the focus and you have a current cell - the same can be observed in the code provided by Rodrigo.
I believe the same thing will be with DataGrid, ListBox, etc. - you need to make sure the control is focused so that typing is performed on the correct element.
Maya
the Telerik team
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Yes, you are right with everything you write. My question is how to trigger the code which focuses the grid and set the current cell.
This would be quite easy in a situation where you have a EventHandler which handles the mouse click on the Add-Button or a command which knows the grid. But not if you have your commands in the ViewModel and want to bind them in XAML.
(imo. just like Dan explained in his Posting on Apr 6, 2011)
Regards
Michael

to my opinion the best approach would be to use custom messages for this purpose. I am guessing you already use them in your project, so the mechanism already exists. The only thing to do is to create a NewItemAdded message, and then all interested parties can subscribe to this message.
This means that if there is some other (ex read-only) view that would like to know if some item is added, it just needs to subscribe to this message.
What will happen in cases where you are just repositioning the item in the list? You would need to remove it and add it to a specific position in collection. UI will think that item is being added, and will try to edit it, which may not be your intention. In case of messages, UI will only edit something IF business layer sent a message that something is added.
This approach will also cover the scenario where several items are added at the same time, so you will have a more general solution to future problems.

I had Messages in my Solution for showing Confirmation- and other Dialogs. I removed and replaced them by by a Concept i found, called DialogService.
So at this point i don't use Messages. Somehow i don't like them, maybe a very personal decision.
But you are right with the issue with repositioning Items when using Rodro's solution. Thanks for the hint.
I guess if i would start again with this Project (or a new, similar one), i would write some commands in the view-layer which can be used command-like in XAML. These commands wold be responsible for calling the ViewModel-Commands and will do view-specific things before and / or after calling the ViewModel-Command. This view-specific things can be things like asking the user if he really wants to do whatever he is up to or set a new added Row to edit mode. This way i could replace quite some "half-clean workarounds" i made already.
Since, until now, we don't have the ability to reorder the grid, i will stick to Rodro's solution for now. Rodro's solution i like much because with this solution things are where they should be (imo). There is no need for the ViewModel to take part in the game of setting new rows to EditMode and that i like much. But on the other side, there is quite a bit of event-registration and deregistration which could become complicated. But since Rodro did the hard work already and posted the result here, its not that complicated anymore.
thanks to all
Michael

well, it highly depends on what kind of project are you working on. If this is a small project which displays only one view at the time, then I guess its ok to use given approach. If it is big project, where multiple views can coexist at the same time, then it would leave unsolved issues (many views can contain information about the entities you are adding / changing, so they need to be aware of the change). I use messages for many things, since I prefer MVVM ViewModelFirst approach, where UI is pretty much dumb, and is instantiated by VM requests through data templates.
there are many ways to skin the cat, you should always go with the technique that can be reused in most scenarios.

@Michael
I'm glad my solution helped you. Yes, wiring the events is a bit complicated and must be done correctly every time... Perhaps one could write a custom derived UserControl to use as a base for the wiews, which would monitor its own DataContextChanged event and automatically wire viewModel's PropertyChanged to a virtual method on the view, so you would have much of the plumbing in place whenever you need it.
@Goran
Ooops! I didn't think about the implications with repositioning the items. And it's something I actually need in my view!
In my case though it's not such a big deal if the moved row becomes editable. But you are right, this could be an issue.
What I don't really like with messaging is that it's too loose. What if I have more than one place in the application where a list of Person is displayed, but I just want to add a Person to a certain list without having all the others to react? Ok, I could specify the target list name in the message or something like that to act as a filter... but I feel like it's a risky solution if some developer forget to filter out unintended messages in their views.
Ciao!

I do not see the problem with this scenario. If you do not want the viewmodel to react to adding a new customer, do not subscribe to this message - actually, by default, all viewmodel's are not subscribed to a particular message, so you will subscribe only in places where you need to be notified. It would be the same if you asked this question: why do I need a MouseOver event, if I do not need it on some places? If you do not need it, do not subscribe to it.
Just try the messenger from MVVM Light, for example. It takes 1-2 minutes to create a message, and after that its a one line code to subscribe to something, and point to a method that will handle it. You do not need to handle any target list, all is done by messenger itself.

I gave up implementing the event-handler and left the problem unsolved. Meanwhile i moved to another sub-project and a colleague took over my work. He now uses messages to solve the problem.
In my new sub-project i faced a similar (actually same) problem again. I used this situation to try a commad-like approach, with two types of commands. I call these ViewCommands and ViewModelCommands. For the first try i implemented (View-) command properties in the code behind of the view (just like one would implement themin the ViewModel when defining CommandProperties in the ViewModel) . These commands can be bound in xaml (just like any other command).
Binding (View-) Command in XAML:
<
controls3:RadButton
Margin
=
"2"
Command
=
"{Binding ElementName=MyRoot, Path=DeleteCommand}"
>
The ViewCommands are responsible to do view-stuff which has to be done before (ViewModel-) Command execution (e.g. remembering ViewState), then calling the ViewModelCommand and then doing view-stuff after (ViewModel-) Command execution (e.g. selecting added rows and stuff or set something to edit mode).
(View-) CommandProperty implementation in Code behind:
// Delete
public ICommand DeleteCommand
{
get
{
return _deleteCommand ??
(
_deleteCommand = new RelayCommand(ExecuteDeleteCommand, CanExectueDeleteCommand)
);
}
}
private void ExecuteDeleteCommand()
{
// Do view stuff before (ViewModel-) Command execution here ...
var vm = DataContext as EntryLotViewModel;
if (vm == null || !vm.DeleteCommand.CanExecute(null)) return;
// ... or here
vm.DeleteCommand.Execute(null);
// Do view stuff after (ViewModel-) Command execution here ...
}
private bool CanExectueDeleteCommand()
{
var vm = DataContext as EntryLotViewModel;
return vm != null && vm.DeleteCommand.CanExecute(null);
}
This is still very basic and there is a lot to be improved (e.g. moving ViewCommands to a (View-) CommandFactory and so on). But this is the way i am going now.
If you see any problems with this approach, i would be glad to hear about it, but so far ... you guess it ;-) ... everything works fine
Thanks to everybody who has taken part in this discussion
Michael