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();
}
}
Related
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).
I'm using MVVM. I bind datagrid to collection with some code:
<commonMVVMControls:GridControl DataContext="{Binding Path=ClientsListGrid,
Mode=TwoWay}"
It's DataGridControl class:
public class GridControl : DataGrid
{
public GridControl()
{
this.DataContextChanged += new System.Windows.DependencyPropertyChangedEventHandler(GridControl_DataContextChanged);
}
void GridControl_DataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
var bindingItemsSource = new Binding("ItemsSource");
bindingItemsSource.Source = this.DataContext;
this.SetBinding(DataGrid.ItemsSourceProperty, bindingItemsSource);
this.RowStyle = new Style(typeof(DataGridRow));
this.RowStyle.Setters.Add(new Setter(DataGridRow.IsSelectedProperty, new Binding("IsSelected")));
}
Now a snippet of code in ViewModel:
var selectedClient = this.ClientsListGrid.ItemsSource.Where(x => x.IsSelected);
if (!selectedClient.Any())
{
MessageBox.Show(Resource.Resource.UpdateUserError, Resource.Resource.Warning, MessageBoxButton.OK, MessageBoxImage.Stop,
MessageBoxResult.OK);
return;
}
var viewModel = new AddOrUpdateClientViewModel(_serviceContext, selectedClient.First());
It works well. But if I scroll datagrid down or up, it stops working and IsSelected always equal false.
Try and see what happens if you disable virtualization. It might have something to do with that.
I have spent considerable amount of time investigating this problem. Any help would be greatly appreciated.
I have a WPF ComboBox declared like this.
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Click="Button_Click">Click Me</Button>
<ComboBox ItemsSource="{Binding ListOfValues}" SelectedItem="{Binding MySelectedItem}" Grid.Row="1">
</ComboBox>
<CheckBox IsChecked="{Binding IsValueChecked}" Grid.Row="2"></CheckBox>
</Grid>
In my code behind, i have these properties and i am implementing the INotifyPropertyChanged
public Window1()
{
InitializeComponent();
ListOfValues = new List<string>();
ListOfValues.Add("apple");
ListOfValues.Add("ball");
ListOfValues.Add("cat");
ListOfValues.Add("dog");
MySelectedItem = "cat";
IsValueChecked = true;
}
public List<string> ListOfValues
{
get
{
return _listOfValues;
}
set
{
_listOfValues = value;
OnPropertyChanged("ListOfValues");
}
}
public string MySelectedItem
{
get
{
return _selectedValueString;
}
set
{
_selectedValueString = value;
OnPropertyChanged("MySelectedItem");
}
}
public bool IsValueChecked
{
get
{
return _isVlaueChanged;
}
set
{
_isVlaueChanged = value;
OnPropertyChanged("IsValueChecked");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MySelectedItem = "dog";
IsValueChecked = !IsValueChecked;
}
The button click event changes the MySelectedItem which is bound to the SelectedItem property of the combobox. But upon the button click nothing gets selected in the combobox. I dont understand why. This happens even if i set explicitly Mode=TwoWay. Please suggest. Note that my datacontext is set to self, so i have confirmed that data binding is happening properly by adding a checkbox
EDIT: Note that this happens in a sample WPF project. But my original project where i want this to work is a winforms app. I am using the elementhost to embed my wpf control. Is that making a difference?
The selected item needs to be set to an object in the list you have it bound to. settings it to a string with a matching value won't work. So try this:
foreach(string animal in ListOfValues)
{
if( animal == "dog")
this.MySelectedItem = animal;
}
I tried to reproduce your problem and I have some questions. Can you please show me your implementation of OnPropertyChanged? When I have a look at the MSDN (http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.onpropertychanged.aspx) this function requires a DependencyPropertyChangedEventArgs as the first parameter, not a string. And in addition, OnPropertyChanged is for notifying about changes in Dependency Properties, not for normal properties.
So I think you overloaded that method to support INotifyPropertyChanged, right?
I tried to implement a working example, this is the result:
public partial class TestWindow2 : Window, INotifyPropertyChanged
{
public TestWindow2()
{
InitializeComponent();
ListOfValues = new List<string> { "apple", "ball", "cat", "dog" };
MySelectedItem = "cat";
IsValueChecked = true;
this.DataContext = this;
}
...
public string MySelectedItem
{
get
{
return _selectedValueString;
}
set
{
_selectedValueString = value;
RaisePropertyChanged("MySelectedItem");
}
}
...
private void Button_Click(object sender, RoutedEventArgs e)
{
MySelectedItem = "dog";
IsValueChecked = !IsValueChecked;
}
private void RaisePropertyChanged(String name)
{
if( this.PropertyChanged != null ) this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Works perfectly for me. When I click the button, dog becoms the selected item in the combo box and the checkbox toggles its state.
If your items are a reference type (and you are just using string for an example), check that the Equals() method is returning what you expect. You might need to override the Equals method (eg this.ID ==other.ID or something like that) to get the correct behavior.
What is the minimum number of steps required to display a tooltip when the following control gets focus?
<TextBox ToolTip="Hello there!" ... />
I tried the following in GotFocus
private void ..._GotFocus(object sender, RoutedEventArgs e) {
var element = (FrameworkElement)sender;
var tooltip = element.ToolTip;
if (!(tooltip is ToolTip)) {
tooltip = new ToolTip { Content = tooltip };
element.ToolTip = tooltip;
}
((ToolTip)tooltip).IsOpen = true;
}
However, it seems to ignore the ToolTipService.Placement for this control and SystemParameters.ToolTipPopupAnimationKey set up level higher.
How can I make it work and honor all settings that generally work for tooltips (except the timing, obviously)?
I'd build an IsKeyboardFocused binding in the attached property, like this:
public class ShowOnFocusTooltip : DependencyObject
{
public object GetToolTip(...
public void SetToolTip(...
public static readonly DependencyProperty ToolTipProperty = DependencyProperty.RegisterAttached(..., new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
ToolTipService.SetToolTip(obj,
e.NewValue==null ? null :
BuildToolTip(obj, e.NewValue));
}
});
private object BuildToolTip(DependencyObject control, object content)
{
var tooltip = content is ToolTip ? (ToolTip)content : new ToolTip { Content = content };
tooltip.SetBinding(ToolTip.IsOpenProperty,
new Binding("IsKeyboardFocusWithin") { Source = control });
return tooltip;
}
Don't have a Windows machine to test, but I would have thought:
<TextBox x:Name="textBox">
<TextBox.ToolTip>
<ToolTip IsOpen="{Binding IsKeyboardFocusWithin, ElementName=textBox}">
Whatever
</ToolTip>
</TextBox.ToolTip>
</TextBox>
I've got an issue with a custom control that I've written not firing it's ContextMenuOpening event when I hook it up programatically. The control is basically a wrapper for the standard TextBox:
public class MyTextBox : TextBox
{
public MyTextBox()
{
this.ContextMenuOpening += new ContextMenuEventHandler(MyTextBox_ContextMenuOpening);
}
void MyTextBox_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
MessageBox.Show("ContextMenuOpening event fired");
}
}
There's nothing suspect either about the XAML:
<local:MyTextBox Height="25" Width="300"/>
For some reason though, I can never get the event to fire. I'm trying to intercept the context menu so I can alter it (it's context sensitive) and really am trying to avoid having to hook up the event everywhere the control is used - surely this is possible?
Turns out you need to explicity set the ContextMenu to null when creating the object:
public MyTextBox()
{
this.ContextMenu = null;
this.Initialized += (s, e) =>
ContextMenuOpening += new ContextMenuEventHandler(MyTextBox_ContextMenuOpening);
}
Then it works a treat :)
The ContextMenuOpening-Event will only be fired after you assign a new context menu to the property ContextMenu:
public MyTextBox()
{
this.ContextMenu = new ContextMenu();
this.ContextMenu.Items.Add(new MenuItem {Header = "Do stuff"});
...
}