How to use from one short key on active tab? - wpf

I have a window that has some tabs,in each tab i can create a new item.
I want define a short key for create new item.But i want my short Key work on active tab.
For example, when Tab1 was active my short key work on create item in Tab1 or when Tab2 was active my short key work on create item in Tab2. How can i use from one short key on active tab?

There are many ways to accomplish this. The most common is to use a command. First, here's the XAML I used:
<Grid>
<TabControl Grid.Row="0"
x:Name="AppTabs">
<TabItem Header="Tab 1">
<ListBox x:Name="TabOneList" />
</TabItem>
<TabItem Header="Tab 2">
<ListBox x:Name="TabTwoList" />
</TabItem>
</TabControl>
</Grid>
Here's the code-behind:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// create the new item command and set it to the shortcut Ctrl + N
var newItemCommand = new RoutedUICommand("New Item", "Makes a new item on the current tab", typeof(MainWindow));
newItemCommand.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control, "Ctrl + N"));
// create the command binding and add it to the CommandBindings collection
var newItemCommandBinding = new CommandBinding(newItemCommand);
newItemCommandBinding.Executed += new ExecutedRoutedEventHandler(newItemCommandBinding_Executed);
CommandBindings.Add(newItemCommandBinding);
}
private void newItemCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
// one way to get the ListBox control from the currently selected tab
ListBox itemList = null;
if (AppTabs.SelectedIndex == 0)
itemList = this.TabOneList;
else if (AppTabs.SelectedIndex == 1)
itemList = this.TabTwoList;
if (itemList == null)
return;
itemList.Items.Add("New Item");
}
I wouldn't consider this production code, but hopefully it points you in the right direction.

Related

XAML - How can I use a KeyBinding command to go to a new line in the textbox?

I am simply trying to move to a new line when Return + Shift are pressed.
I got this much from a previous post on here:
<TextBox.InputBindings>
<KeyBinding Key="Return" Modifiers="Shift" Command=" " />
</TextBox.InputBindings>
But I cannot find anywhere that explains how to accomplish the move to a new line within the textbox.
I cannot use the: AcceptsReturn="True" as I want return to trigger a button.
If you don't have an ICommand defined, you can attach a handler for the UIElement.PreviewKeyUp event to the TextBox. Otherwise you will have to define an ICommand implementation and assign it to the KeyBinding.Command so that the KeyBinding can actually execute. Either solution finally executes the same logic to add the linebreak.
You then use the TextBox.AppendText method to append a linebreak and the TextBox.CaretIndex property to move the caret to the end of the new line.
MainWindow.xaml
<Window>
<TextBox PreviewKeyUp="TextBox_PreviewKeyUp" />
</Window>
MainWindow.xaml.cs
partial class MainWindow : Window
{
private void TextBox_PreviewKeyUp(object sender, KeyEventArgs e)
{
if (!e.Key.Equals(Key.Enter)
|| !e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Shift))
{
return;
}
var textBox = sender as TextBox;
textBox.AppendText(Environment.NewLine);
textBox.CaretIndex = textBox.Text.Length;
}
}
I found a nice way to do it without using an ICommand.
Simply added this PreviewKeyDown event onto the control in xaml:
PreviewKeyDown="MessageText_PreviewKeyDown"
And this is the C# behind:
private void MessageText_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
// Get the textbox
var textbox = sender as TextBox;
// Check if we have pressed enter
if (e.Key == Key.Enter && Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
{
// Add a new line where cursor is
var index = textbox.CaretIndex;
// Insert a new line
textbox.Text = textbox.Text.Insert(index, Environment.NewLine);
// Shift the caret forward to the newline
textbox.CaretIndex = index + Environment.NewLine.Length;
// Mark this key as handled by us
e.Handled = true;
}
}

Programatically Select a combobox item using the SelectedValue WPF

I have a combo box which is loaded through a Datasource(Datatable). On a scenario I want the combo box to load with the desired value which I would be passing as combobox1.SelectedValue = custId (Say it's a customer details). custID is set as SelectedValuePath in XAML. When I set that, I am getting a null exception. Anything I am missing?
My XAML:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="332,42,0,0" Name="cmbCustomerName" VerticalAlignment="Top" Width="240" IsEditable="True" DisplayMemberPath="customername" SelectedValuePath="custid" ItemsPanel="{StaticResource cust}" SelectionChanged="cmbCustomerName_SelectionChanged" AllowDrop="True" FontWeight="Normal" Text="--Select a Customer Name--" IsSynchronizedWithCurrentItem="True" />
UPDATE:
C# code:
public customer(int custid)
{
InitializeComponent();
cmbcustomer.SelectedValue= custid.ToString();
}
private void cmbCustomerName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
cmbcustid.SelectedValue= cmbcustomer.SelectedValue;
}
The selectedValue would not work in this scenario,you should use selectedItem instead,for example:
combobox1.SelectedItem = "custId";
or
combobox1.Text = "custId";
or
combobox1.SelectedIndex = combobox1.Items.IndexOf("custId");
or
combobox1.SelectedIndex = combobox1.FindStringExact("custId")
I will suggest you a method
This is hackish. This is bad coding format.
// Remove the handler
cmbcustomer.SelectionChanged -= cmbCustomerName_SelectionChanged;
// Make a selection...
cmbcustomer.SelectedIndex = combobox1.Items.IndexOf(custid.ToString()); //<-- do not want to raise
// SelectionChanged event programmatically here
// Add the handler again.
cmbcustomer.SelectionChanged += cmbCustomerName_SelectionChanged;
As a temporary solution you can try this out
Wait to access any properties of the ComboBoxes until the they have been loaded:
private void cmbCustomerName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(cmbcustid != null && cmbcustid.IsLoaded && cmbcustomer != null && cmbcustomer.IsLoaded)
cmbcustid.SelectedValue = cmbcustomer.SelectedValue;
}
I got the issue resolved by assigning the value in the combox_loaded event, as the combobox was just initialized in the constructor, but it was not loaded from the datasource.

wpf autocompletebox default dropdown area is too small

I set the autocompletebox just like this:
<StackPanel Orientation="Horizontal">
<StackPanel Width="120">
<Label Content="Address"/>
<Controls:AutoCompleteBox x:Name="AddressBox" MaxDropDownHeight="300" Populating="Address_Populating"/>
</StackPanel>
<StackPanel Width="120" Margin="40, 0, 0, 0">
<Label Content="Port"/>
<TextBox x:Name="PortBox" />
</StackPanel>
<Button x:Name="ConnectButton" Content="Connect" Margin="40, 0, 0, 0" VerticalAlignment="Bottom" Width="80" Height="35" Click="ConnectButton_Clicked"/>
</StackPanel>
But the max number of items displayed in the dropdown window is only 3. I am sure that the candidate number is larger than 3. I want to increase the number of items which will be displayed in the dropdown window.
For example, i want to show 15 candidateAddress's items. And the dropdown window will be displayed and 3 items will be showed firstly. But I hope it can show 5 items firstly, which means that the display area should be expanded.
The logical code of this control is:
private void Address_Populating(object sender, PopulatingEventArgs e)
{
string dirFile = "../../Config/Address.config";
if (File.Exists(dirFile))
{
var candidateAddress = new List<string>();
string input = null;
using (StreamReader sr = File.OpenText(dirFile))
{
while ((input = sr.ReadLine()) != null)
{
candidateAddress.Add(input);
}
}
AddressBox.ItemsSource = candidateAddress;
AddressBox.PopulateComplete();
}
else
{
System.Windows.MessageBox.Show("Address.config does not exist");
}
}
i can't add a pic to comment. so i add it here.
top pic : MaxDropDownHeight=50
bottom: MaxDropDownHeight=300
you mean like this?
you can creat a new project:
<Grid>
<control:AutoCompleteBox x:Name="AddressBox" FontSize="30" MaxDropDownHeight="300"
Populating="Address_Populating" Margin="0,0,0,287.283" />
</Grid>
background code:
private void Address_Populating(object sender, PopulatingEventArgs e)
{
List<int> lst = new List<int>();
for (int i = 10; i < 25; i++)
{
lst.Add(i);
}
AddressBox.ItemsSource = lst;
AddressBox.PopulateComplete();
}
the reason is found by kylejan:
i found the reason. the display area will be influenced by the former window. for example, the window i put this control on is opend by the main window. then this autocomplete box will be influenced by the size of the main window
There is no easy way (included in the Framework) to exactly set the number of items to be displayed. But this example gives you some code to create an attached property that manipulates the maxheight property in order to display any specified number of items.

DatagridTemplate column content only visible when row selected and cell clicked

Hi I have a Datagrid that is bound to an ObservableCollection of custom AutoCAD layer objects. 3 of the columns are DataGridTextColumns and work correctly. However I also have a DataGridTemplateColumn that contains a StackPanel containing a label and a Rectangle. I am using the label to display the ACI or RGB value of the layer depending how it is set and displaying the colour in the rectangle. The rectangle has a mouse down event that launches a colour picker dialog so the user can select a new colour for the layer. This functionality works. What doesn't work is that the contents of the cell (the label and rectangle) are only shown in a row that is selected and the cell clicked on whereas they need to be visible at all times.
I have tried using a Grid inside the DataTemplate and using the Grid's FocusManager.Focused element to give the Rectangle Focus but this hasn't changed the behaviour.
<t:DataGrid x:Name="layersGrid" ItemsSource="{Binding Layers}"
SelectedItem="{Binding SelectedLayer, Mode=TwoWay}" SelectionMode="Single">
<t:DataGridTemplateColumn Visibility="Visible">
<t:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Grid FocusManager.FocusedElement="{Binding ElementName=swatch}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Colour.ColourProperty}"/>
<Rectangle Name="swatch" Fill="{Binding Colour, Converter={StaticResource colourConverter}}"
MouseLeftButtonDown="swatch_MouseLeftButtonDown"/>
</StackPanel>
</Grid>
</DataTemplate>
</t:DataGridTemplateColumn.CellEditingTemplate>
</t:DataGridTemplateColumn>
</t:DataGrid.Columns>
</t:DataGrid>
Additionally, once you change the colour of the layer in the model view, the rectangle hasn't updated until another row is selected and then the changed one is selected again.
private void swatch_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Colour col = LaunchColourPickerCode();
((LayersModel)this.Resources[MODEL]).SelectedLayer.Colour = col;
}
The problem with them not displaying has been fixed by using CellTemplate instead of a CellEditingTemplate
I adapted surfen's answer on this page to solve the selection problem
How to perform Single click checkbox selection in WPF DataGrid?
Replacing his method with this:
private static void GridColumnFastEdit(DataGridCell cell, RoutedEventArgs e)
{
if (cell == null || cell.IsEditing || cell.IsReadOnly)
return;
DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
if (dataGrid == null)
return;
if (!cell.IsFocused)
{
cell.Focus();
}
DataGridRow row = FindVisualParent<DataGridRow>(cell);
if (row != null && !row.IsSelected)
{
row.IsSelected = true;
}
}
and adding an event on the swatch to obtain the cell it is in
private void swatch_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = null;
while (cell == null)
{
cell = sender as DataGridCell;
if (((FrameworkElement)sender).Parent != null)
sender = ((FrameworkElement)sender).Parent;
else
sender = ((FrameworkElement)sender).TemplatedParent;
}
GridColumnFastEdit(cell, e);
}
Also thanks to kmatyaszek

How to add a new line on TAB key in WPF dataGrid

I want to add a new line in my datagrid when I press 'TAB' key on last cell of the datagrid.
I am using MVVM pattern to do this. I have came with a solution, I assinged Tab key to the Input binding of the datagrid:
<DataGrid.InputBindings>
<KeyBinding Command="{Binding Path=InsertNewLineCommand}" Key="Tab"></KeyBinding>
</DataGrid.InputBindings>
And added following code to InsertNewLineCommand:
private void ExecuteInsertNewLineCommand()
{
//Checked is SelectedCell[0] at last cell of the datagrid
{
InsertNewLine();
}
}
But the problem is ON ADDING KEYBINDING='TAB' MY NORMAL TAB FEATURE ON THE GRID DISABLES (MOVING TO NEXT CELL AND SO...)
Just determine if you are on the last column then execute your command.
I am using PreviewKeyDown, so I could test the logic, but you can put that in your executeCommand method. Anyway, this should get you started:
<DataGrid PreviewKeyDown="DataGrid_PreviewKeyDown" SelectionUnit="Cell" ....
private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (!Keyboard.IsKeyDown(Key.Tab)) return;
var dataGrid = (DataGrid) sender;
var current = dataGrid.Columns.IndexOf(dataGrid.CurrentColumn);
var last = dataGrid.Columns.Count - 1;
if (current == last)
ExecuteInsertNewLineCommand();
}

Resources