Reputation: 15
I have searched everywhere and cannot find an answer to this. Using a WPF DataGrid bound to a Web API http://localhost:3000/api/profiles, and how to keep focus on row after reloading data?
public class ProfilesViewModel : BaseViewModel
{
private ObservableCollection<Profile> _Items;
public ObservableCollection<Profile> Profiles { get => _Items; set { _Items = value; OnPropertyChanged(); } }
public PartyProfilesViewModel()
{
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 100);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
var client = new RestClient("http://localhost:3000");
var reqData = new RestRequest("api/profiles", Method.GET);
client.ExecuteAsync(reqData, resData =>
{
Profiles = JsonConvert.DeserializeObject<ObservableCollection<Profile>>(resData.Content);
});
}
}
Thanks!
Upvotes: 1
Views: 655
Reputation: 12276
I think you'll find you don't get focus back on the datagrid row if you just set selecteditem. You'll need a behavior or code behind. Here's what I use:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace wpf_EntityFramework
{
/// <summary>
/// Attached Behavior
/// Somewhat trickier than a regular behavior because it's to be attached via a style
/// </summary>
class DataGridRowBehavior : Behavior<DataGridRow>
{
public static bool GetIsDataGridRowFocussedWhenSelected(DataGridRow dataGridRow)
{
return (bool)dataGridRow.GetValue(IsDataGridRowFocussedWhenSelectedProperty);
}
public static void SetIsDataGridRowFocussedWhenSelected(
DataGridRow dataGridRow, bool value)
{
dataGridRow.SetValue(IsDataGridRowFocussedWhenSelectedProperty, value);
}
public static readonly DependencyProperty IsDataGridRowFocussedWhenSelectedProperty =
DependencyProperty.RegisterAttached(
"IsDataGridRowFocussedWhenSelected",
typeof(bool),
typeof(DataGridRowBehavior),
new UIPropertyMetadata(false, OnIsDataGridRowFocussedWhenSelectedChanged));
static void OnIsDataGridRowFocussedWhenSelectedChanged(
DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
DataGridRow item = depObj as DataGridRow;
if (item == null)
return;
if (e.NewValue is bool == false)
return;
if ((bool)e.NewValue)
item.Selected += OndataGridRowSelected;
else
item.Selected -= OndataGridRowSelected;
}
static void OndataGridRowSelected(object sender, RoutedEventArgs e)
{
DataGridRow row = e.OriginalSource as DataGridRow;
// If focus is already on a cell then don't focus back out of it
if (!(Keyboard.FocusedElement is DataGridCell) && row != null)
{
row.Focusable = true;
Keyboard.Focus(row);
}
}
}
}
and
using System;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace wpf_EntityFramework
{
class ScrollDataGridRowIntoView : Behavior<DataGrid>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
}
void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is DataGrid)
{
DataGrid datagrid = (sender as DataGrid);
if (datagrid.SelectedItem != null)
{
datagrid.Dispatcher.BeginInvoke((Action)(() =>
{
datagrid.UpdateLayout();
if (datagrid.SelectedItem != null)
{
datagrid.ScrollIntoView(datagrid.SelectedItem);
}
}));
}
}
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
}
}
}
Usage
<DataGrid ....
>
<i:Interaction.Behaviors>
<local:ScrollDataGridRowIntoView />
</i:Interaction.Behaviors>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="local:DataGridRowBehavior.IsDataGridRowFocussedWhenSelected" Value="true"/>
</Style>
</DataGrid.RowStyle>
Upvotes: 0
Reputation: 7325
Add in ViewModel a property for selected item:
private _currentProfile=null;
public Profile CurrentProfile { get => _currentProfile; set { CurrentProfile = value; OnPropertyChanged(); } }
Extend your lambda(Equals()
must be implemented for Profile
):
client.ExecuteAsync(reqData, resData =>
{
var curProf = CurrentProfile;
Profiles = JsonConvert.DeserializeObject<ObservableCollection<Profile>>(resData.Content);
CurrentProfile=Profiles.FirstOrDefault((p)=>p.Equals(curProf));
});
And bind CurrentProfile
to the DataGrid.SelectedItem
in XAML:
<DataGrid ItemsSource="{Binding Profiles}" SelectionMode="Single" SelectedItem="{Binding CurrentProfile, Mode=TwoWay}">
</DataGrid>
Upvotes: 1