Prevent jumping to next row when user hits Enter in RadGridView - wpf

I have a RadGridView from Telerik UI for WPF with an editable column. When user edits a cell in that column and hits Enter, the same cell in next row in the grid gets focus.
I want the cell that the user just edited to lose focus. How to do this MVVM-style?

You can change this behavior by writing a custom keyboard command provider. This provider overrides the default Enter press action. It commits the edits and deselects the cellby setting the SelectedItem to null.
public class CustomKeyboardCommandProvider : DefaultKeyboardCommandProvider
{
private readonly GridViewDataControl _grid;
public CustomKeyboardCommandProvider(GridViewDataControl grid)
: base(grid)
{
_grid = grid;
}
public override IEnumerable<ICommand> ProvideCommandsForKey(Key key)
{
var commands = base.ProvideCommandsForKey(key).ToList();
if (key != Key.Enter)
return commands;
commands.Clear();
commands.Add(RadGridViewCommands.CommitEdit);
_grid.SelectedItem = null;
return commands;
}
}
You have to assign the new provider. The easiest way is in code-behind, as it has a constructor parameter.
MyRadDataGridView.KeyboardCommandProvider = new CustomKeyboardCommandProvider(TestGridView);
Alternatively, create a TriggerAction<RadGridView> and attach it to the Loaded event of the grid view.
public class SetCustomKeyboardCommandProviderAction : TriggerAction<RadGridView>
{
protected override void Invoke(object parameter)
{
AssociatedObject.KeyboardCommandProvider = new CustomKeyboardCommandProvider(AssociatedObject);
}
}
<telerik:RadGridView>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Loaded">
<local:SetCustomKeyboardCommandProviderAction/>
</b:EventTrigger>
</b:Interaction.Triggers>
<!-- ...other definitions. -->
</telerik:RadGridView>

Related

Handle Got_Focus & Lost_Focus for Popup inside of DataGrid

I have a DataGrid which has more options popup as a last column. When I click on a last cell of a row (more options popup icon) popup will get focused and show up, however instantly after that the row itself gets selected and will take focus away from popup which will cause the popup to close. In order to open it again I have to click twice on it.
It could be fixed by setting SelectionMode="None", but I want my rows to be selectable. Another workaround could be to try control focuses on events, but it also doesn't give an expected behavior:
PopupBox selectedPopupBox;
public CustomersView()
{
InitializeComponent();
}
private void PopupBox_GotFocus(object sender, RoutedEventArgs e)
{
var popupBox = sender as PopupBox;
selectedPopupBox = popupBox;
popupBox.IsPopupOpen = true;
}
private void CustomersDataGrid_SelectionChanged(object sender, GridSelectionChangedEventArgs e)
{
if (selectedPopupBox != null)
{
selectedPopupBox.Focus();
popupBox.IsPopupOpen = true;
}
}
The problem with the solution would be that whenever another row will be selected previous popup will be opened.
Similar problems I found: Syncfusion forum, Stackoverflow question
P.S. I don't want to open a popup when any other cell on a row is clicked, only when more options icon is clicked.
Attaching current behaviors to make it more clear:
Default behavior:
SelectionMode is set to None:
Workaround with code behind:
The solution to this problem was the answer from sf forum.
public partial class CustomersView : UserControl
{
public CustomersView()
{
InitializeComponent();
this.customersDataGrid.CellRenderers.Remove("TemplateExt");
this.customersDataGrid.CellRenderers.Add("TemplateExt", new GridCellTemplateExtension());
}
}
// Create Grid template column extension and specify it's cell type
public class MoreOptionsTemplateColumnExtension : GridTemplateColumn
{
public MoreOptionsTemplateColumnExtension()
{
SetCellType("TemplateExt");
}
}
public class GridCellTemplateExtension : GridCellTemplateRenderer
{
// This method will set the focus to the clicked cell
// instead of row itself
protected override void SetFocus(FrameworkElement uiElement, bool needToFocus)
{
if (!needToFocus)
DataGrid.Focus();
}
}
And you can you use this extension in your XAML like this:
<local:MoreOptionsTemplateColumnExtension Width="85"
AllowFocus="True"
AllowSorting="False">
<local:MoreOptionsTemplateColumnExtension.CellTemplate>
<DataTemplate>
<md:PopupBox Margin="5"
Padding="2,0,2,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="DarkSlateGray"
PopupMode="Click">
<!-- Your popup content -->
</md:PopupBox>
</DataTemplate>
</local:MoreOptionsTemplateColumnExtension.CellTemplate>
</local:MoreOptionsTemplateColumnExtension>

WPF Button with Multiple Content

I am new in WPF,I am using Button control in WPF windows application, I am displaying its content from Database,
I have its click event binded with its Name,like this
<Button Content="{Binding FirstName}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="628,178,0,0" x:Name="btn1Click"/>
This button have different content for each user.
This is my FirstName property
string _fname;
public string FirstName
{
get { return _fname; }
set { _fname= value; NotifyOfPropertyChange("FirstName"); }
}
I want to get ID of the clicked user, how can I put UserID in content(with firstname)?
or in x:Name so I can identify which user is clicked?
Or I can use some hidden field for it and how?
You can bind a property to commandParameter and can check where you have binded the command to the event handler. like
<Button Command="{Binding BtnClickCommand}" CommandParameter="{Binding Id}" />
In ViewModel of this view:
BtnClickCommand=new RelayCommand(o=>BtnClickEvent((string)o));// Cast you id to whatever data type u have.
private void BtnClickEvent(string Id)
{
//Here you got your id and do what u want..
}
Assign DataContext property of button's parent with the user object then in the click event of a button write following code.
private void Button_Click(object sender, RoutedEventArgs e)
{
Button item = sender as Button;
if(item != null)
{
//you will get user details here by using item.DataContext property
User clickedUser = item.DataContext as User;
}
}
Here you will get all the details of Clicked User.

WPF binding to custom control (textbox) not working

i wrote a simple custom control that inherits from textbox and uses a custom inputbox to enter text:
class TextTextbox : TextBox
{
public string InputBoxTitle { get; set; }
public string Input { get; set; }
public TextTextbox()
{
PreviewMouseDown += MyTextbox_MouseDown;
}
private void MyTextbox_MouseDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
TextBox tb = (TextBox)sender;
var dialog = new BFH.InputBox.InputBox(InputBoxTitle, Input);
dialog.ShowDialog();
if (!dialog.Canceled)
tb.Text = dialog.Input;
else
tb.Text = Input;
}
}
i use it in the view like this:
<CustomControls:TextTextbox Text="{Binding Test}" InputBoxTitle="Titel" Input="Input"/>
in the vm for tests:
private string _test;
public string Test
{
get { return _test; }
set
{
if (_test == value)
return;
_test = value;
RaisePropertyChanged("Test");
}
}
but the binding to Test is not working. in the view, i see that the text of the textbox does change, but i seems not to be linked to the property of the VM. i added a button with MessageBox.Show(Test), but it is always empty. what am i doing wrong here?
You need to set the binding's UpdateSourceTrigger property to PropertyChanged. Otherwise the source property Test will not be updated before the TextBox loses focus.
<CustomControls:TextTextbox
Text="{Binding Test, UpdateSourceTrigger=PropertyChanged}" ... />
From the Examples section on the Binding.UpdateSourceTrigger page on MSDN:
The TextBox.Text property has a default UpdateSourceTrigger value of
LostFocus. This means if an application has a TextBox with a
data-bound TextBox.Text property, the text you type into the TextBox
does not update the source until the TextBox loses focus (for
instance, when you click away from the TextBox).

Turn off autoComplete in Combobox in wpf

I am using .NET framework 4.0 to build my application.
I have a combobox in which I want to turn off suggest-append mode of combobox. Instead I want suggest-only mode.
In many questions users ask for turning autoComplete feature off and everywhere I got the same answer. i.e. set IsTextSearchEnabled to False.
When IsTextSearchEnabled = True
When IsTextSearchEnabled = False
What I want is :
When User Presses Enter on the Combobox I want the Item to be appended to the textbox of the combobox.
Is this thing possible in WPF?
Like promised here is the demo. As you can see I did what I explained in my comments. I listened to text changed event.
Check it out:
<Grid>
<local:MyComboBox x:Name="comboBox" IsEditable="True"
VerticalAlignment="Center"
IsTextSearchEnabled="True">
<ComboBoxItem>hello</ComboBoxItem>
<ComboBoxItem>world</ComboBoxItem>
<ComboBoxItem>123</ComboBoxItem>
</local:MyComboBox>
</Grid>
public class MyComboBox : ComboBox
{
private string myValue;
private bool needsUpdate;
public override void OnApplyTemplate()
{
TextBox tbx = this.GetTemplateChild("PART_EditableTextBox") as TextBox;
tbx.PreviewKeyDown += (o, e) =>
{
this.needsUpdate = true;
};
tbx.TextChanged += (o, e) =>
{
if (needsUpdate)
{
myValue = tbx.Text;
this.needsUpdate = false;
}
else
{
tbx.Text = myValue;
}
};
base.OnApplyTemplate();
}
}

ListBox SelectedItem binded: page navigation, getting item, showing its properties in a new view and reset SelectedIndex. How can i do?

i'm trying to apply the MVVM pattern in my application with MVVM Light. I've a databinded ListBox...
MainView.xaml [extract]
<ListBox Name="recipesListBox"
ItemsSource="{Binding RecipeList}"
SelectedItem="{Binding SelectedRecipe, Mode=TwoWay}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Row="1"
Margin="12,0,12,0"
SelectionChanged="recipesListBox_SelectionChanged" >
MainViewModel.cs [extract]
private Recipe selectedRecipe;
public Recipe SelectedRecipe
{
get
{
return selectedRecipe;
}
set
{
selectedRecipe = value;
RaisePropertyChanged("SelectedRecipe");
}
}
...that performs a page navigation on SelectionChanged:
MainView.xaml.cs [extract]
private void recipesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string destination = "/RecipeView.xaml";
if (recipesListBox.SelectedIndex == -1) // If selected index is -1 (no selection) do nothing
return;
this.NavigationService.Navigate(new Uri(destination, UriKind.Relative));
//recipesListBox.SelectedIndex = -1; // Reset selected index to -1 (no selection)
}
After // you can see the old code that reset the index after page navigation - now, with binded data, obviously it also set null my selected item! How can i do for navigate to a new view, show the property of selected item and reset the selected index when i go back? Thank you!
The way I did it was this:
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
if (listBox.SelectedItem != null)
{
listBox.SelectedIndex = -1;
}
base.OnNavigatedFrom(e);
}
then add the following to SelectionChanged event
if(SelectedItem != null)
{
// Do something with SelectedItem
}
The best way is to have your collection stored somewhere you can access it anywhere (like in the Windows Phone Databound Application project) and pass the index of the selected item in your navigation uri
int index = recipesListBox.SelectedIndex;
this.NavigationService.Navigate(new Uri(destination +"?index="+index , UriKind.Relative));
Then in the OnNavigatedTo method of your new page get the index from the query and get the item
override OnNavigatedTo(
{
string index;
if(NavigationContext.QueryString.TryGetValue("index", index))
{
// get the item from your collection based on this index
}
}

Resources