I have a Auto-Complete TextBox like this:
public class AutoCompleteTextBox:ComboBox
{
public AutoCompleteTextBox()
{
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri("/"+this.GetType().Assembly.GetName().Name+";component/Styles/MainViewStyle.xaml",UriKind.Relative);
this.Resources = rd;
this.IsTextSearchEnabled = false;
}
/// <summary>
/// Override OnApplyTemplate method
/// Get TextBox control out of Combobox control, and hook up TextChanged event.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//get the textbox control in the ComboBox control
TextBox textBox = this.Template.FindName("PART_EditableTextBox", this) as TextBox;
if (textBox != null)
{
//disable Autoword selection of the TextBox
textBox.AutoWordSelection = false;
//handle TextChanged event to dynamically add Combobox items.
textBox.TextChanged += new TextChangedEventHandler(textBox_TextChanged);
}
}
public ObservableCollection<string> SuggestionList
{
get { return (ObservableCollection<string>)GetValue(SuggestionListProperty); }
set { SetValue(SuggestionListProperty, value); }
}
public static readonly DependencyProperty SuggestionListProperty = DependencyProperty.Register("SuggestionList", typeof(ObservableCollection<string>), typeof(AutoCompleteTextBox), new UIPropertyMetadata());
/// <summary>
/// main logic to generate auto suggestion list.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/>
/// instance containing the event data.</param>
void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
textBox.AutoWordSelection = false;
// if the word in the textbox is selected, then don't change item collection
if ((textBox.SelectionStart != 0 || textBox.Text.Length == 0))
{
this.Items.Clear();
//add new filtered items according the current TextBox input
if (!string.IsNullOrEmpty(textBox.Text))
{
foreach (string s in this.SuggestionList)
{
if (s.StartsWith(textBox.Text, StringComparison.InvariantCultureIgnoreCase))
{
string unboldpart = s.Substring(textBox.Text.Length);
string boldpart = s.Substring(0, textBox.Text.Length);
//construct AutoCompleteEntry and add to the ComboBox
AutoCompleteEntry entry = new AutoCompleteEntry(s, boldpart, unboldpart);
this.Items.Add(entry);
}
}
}
}
// open or close dropdown of the ComboBox according to whether there are items in the
// fitlered result.
this.IsDropDownOpen = this.HasItems;
//avoid auto selection
textBox.Focus();
textBox.SelectionStart = textBox.Text.Length;
}
}
/// <summary>
/// Extended ComboBox Item
/// </summary>
public class AutoCompleteEntry : ComboBoxItem
{
private TextBlock tbEntry;
//text of the item
private string text;
/// <summary>
/// Contrutor of AutoCompleteEntry class
/// </summary>
/// <param name="text">All the Text of the item </param>
/// <param name="bold">The already entered part of the Text</param>
/// <param name="unbold">The remained part of the Text</param>
public AutoCompleteEntry(string text, string bold, string unbold)
{
this.text = text;
tbEntry = new TextBlock();
//highlight the current input Text
tbEntry.Inlines.Add(new Run
{
Text = bold,
FontWeight = FontWeights.Bold,
Foreground = new SolidColorBrush(Colors.RoyalBlue)
});
tbEntry.Inlines.Add(new Run { Text = unbold });
this.Content = tbEntry;
}
/// <summary>
/// Gets the text.
/// </summary>
public string Text
{
get { return this.text; }
}
}
And my xaml looks like this:
<local:AutoCompleteTextBox SuggestionList="{Binding Suggestions}"
Text="{Binding Path=Keyword,UpdateSourceTrigger=PropertyChanged}"
x:Name="SearchTextBox"/>
When I press enter button, I want to execute search command, but if the suggestion combobox on the screen, press enter button only close the suggestion combobox, I need to press enter button again to execute the command. Is there a way to close the suggestion combobox and execute the command with pressing enter button one time?
Thanks
You can invoke the search when handling the DropDownClosed event.
<local:AutoCompleteTextBox SuggestionList="{Binding Suggestions}"
Text="{Binding Path=Keyword,UpdateSourceTrigger=PropertyChanged}"
DropDownClosed="OnDropDownClosed"
x:Name="SearchTextBox"/>
And OnDropDownClosed:
private void OnDropDownClosedobject sender, RoutedPropertyChangedEventArgs<bool> e)
{
// search on Keyword
}
Related
My code creates multiple buttons with a certain color. When I click a button I want it to change to a HEX color and it works well. The problem is that when I click in another button, I want the previously selected button to go back to the default color scheme.
private void createButtons()
{
foreach (int axis_number in axis_sequence.number)
{
AxisSequence axis = new AxisSequence (axis_number);
axis.MouseLeftButtonDown += new MouseButtonEventHandler (axis_MouseLeftButtonDown);
axis_sequence.Children.Add (axis);
}
}
void axis_MouseLeftButtonDown (object sender, MouseButtonEventArgs e)
{
var converter = new System.Windows.Media.BrushConverter();
var brush_amob_gray = (System.Windows.Media.Brush)converter.ConvertFromString("#515151");
var brush_amob_orange = (System.Windows.Media.Brush)converter.ConvertFromString("#FF8C00");
((AxisSequence)sender).change_canvas = brush_amob_orange;
((AxisSequence)sender).change_text_color = System.Windows.Media.Brushes.Black;
//When I click another button I wanted to all the others to the default Colors.
AXIS SEQUENCE:
public partial class AxisSequence : UserControl
{
/// <summary>
///
/// </summary>
/// <param name="numero_eixo"></param>
public AxisSequence (int numero_eixo)
{
try
{
InitializeComponent();
Value.Content = numero_eixo.ToString();
}
catch (System.Exception ex)
{
System.Windows.MessageBox.Show(ex.ToString());
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public int get_numero_eixo ()
{
return Int32.Parse (Value.Content.ToString());
}
/// <summary>
///
/// </summary>
public System.Windows.Media.Brush change_canvas { get { return canvas.Background; } set { canvas.Background = value; } }
/// <summary>
///
/// </summary>
public System.Windows.Media.Brush change_text_color { get { return Value.Foreground; } set { Value.Foreground = value; } }
}
I want to create a editable Spinner (or Picker in Xamarin.Forms).
I have a custom renderer for my element (derived from Picker) that render the Picker as AutoCompleteTextView. Inside the renderer i have created AutoCompleteTextView that shows the dropdown menue if it on focus or is been clicked. Its worked fine.
My problem is that it shows like a EditText (or Entry in Xamarin.Forms) control on device, but i want to display it like a Spinner (or Picker on Xamarin.Forms).
Any idea how i have to make this?
EDIT:
Here what i do in UWP:
Custom Renderer for UWP control:
CustomEditablePicker customControl; // Derived from Xamarin.Forms.Picker
ComboBox nativeControl; // Windows.UI.Xaml.Controls.ComboBox
TextBox editControl;
protected override void OnElementChanged(ElementChangedEventArgs<CustomEditablePicker> e)
{
base.OnElementChanged(e);
customControl = e.NewElement;
nativeControl = new ComboBox();
editControl = new TextBox(); // First element of CheckBox would be a TextBox for edit some Text
// Set the style (declarated in App.xaml)
Style editableStyle = App.Current.Resources["ComboBoxItemTextBox"] as Style;
if (editableStyle != null)
{
editControl.Style = editableStyle;
ComboBoxItem item = new ComboBoxItem();
item.IsSelected = true; // Select First element
item.Content = editControl; // TextBox as content for first element
nativeControl.Items.Add(item);
nativeControl.SelectionChanged += NativeControl_SelectionChanged; // Do something if selection is changed
}
// Add items from custom element to native element
foreach (var item in customControl.Items)
{
nativeControl.Items.Add(item);
}
editControl.KeyDown += EditControl_KeyDown; // Handle the space key
editControl.TextChanged += EditControl_TextChanged; // Handle something if text inside TextBox is changed
base.SetNativeControl(nativeControl); // Set native control to be displayed
}
/// <summary>
/// Set text for Picker if value is changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EditControl_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox edit = (sender as TextBox);
customControl.Text = edit.Text;
}
/// <summary>
/// Handle Space-Key, without handle this key the ComboBox would be lost focus
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EditControl_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Space)
{
if (editControl.SelectionLength > 0)
{
editControl.Text = editControl.Text.Remove(editControl.SelectionStart, editControl.SelectionLength);
editControl.SelectionLength = 0;
}
int pos = editControl.SelectionStart;
editControl.Text = editControl.Text.Insert(pos, " ");
editControl.SelectionStart = pos + 1;
e.Handled = true;
}
}
/// <summary>
/// Occurs when selection of the box is changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void NativeControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count == 1 && e.AddedItems[0] != (sender as ComboBox).Items[0])
{
(sender as ComboBox).SelectedIndex = 0;
editControl.Text = e.AddedItems[0] as String;
}
}
And The control in the PCL (Xamarin.Forms):
public class CustomEditablePicker : Picker
{
public static readonly BindableProperty EditTextProperty = BindableProperty.Create<CustomEditablePicker, string>(c => c.Text, String.Empty, BindingMode.TwoWay, propertyChanged: OnTextChanged);
public event EventHandler<CustomUIEventArgs<string>> TextChanged;
public static readonly BindableProperty Source = BindableProperty.Create<CustomEditablePicker, IEnumerable<string>>(l => l.ItemsSource, new List<string>(), BindingMode.TwoWay, propertyChanged: OnSourceChanged);
private static void OnSourceChanged(BindableObject bindable, IEnumerable<string> oldValue, IEnumerable<string> newValue)
{
CustomEditablePicker customEditablePicker = (CustomEditablePicker)bindable;
customEditablePicker.ItemsSource = newValue;
}
public event EventHandler<CustomUIEnumerableArgs<IEnumerable<string>>> SourceChanged;
public IEnumerable<string> ItemsSource
{
get { return (List<string>)this.GetValue(Source); }
set
{
if (this.ItemsSource != value)
{
this.SetValue(Source, value);
if (SourceChanged != null)
{
this.SourceChanged.Invoke(this, new CustomUIEnumerableArgs<IEnumerable<string>>(value));
}
}
}
}
public string Text
{
get { return (string)this.GetValue(EditTextProperty); }
set
{
if (this.Text != value)
{
this.SetValue(EditTextProperty, value);
if (TextChanged != null)
{
// Raise a event, with changed text
this.TextChanged.Invoke(this, new CustomUIEventArgs<string>(value));
}
}
}
}
private static void OnTextChanged(BindableObject bindable, string oldValue, string newValue)
{
CustomEditablePicker customEditablePicker = (CustomEditablePicker)bindable;
customEditablePicker.Text = newValue;
}
}
To show image inside EditText, use SetCompoundDrawablesWithIntrinsicBounds:
protected override void OnElementChanged(ElementChangedEventArgs<SoundsPicker> e)
{
if (e.NewElement != null)
{
if (base.Control == null)
{
EditText editText = new EditText(Context)
{
Focusable = false,
Clickable = true,
Tag = this
};
var padding = (int)Context.ToPixels(10);
// that show image on right side
editText.SetCompoundDrawablesWithIntrinsicBounds(0, 0, Resource.Drawable.arrow_down, 0);
editText.CompoundDrawablePadding = padding;
editText.SetOnClickListener(MyPickerPickerListener.Instance);
editText.SetBackgroundDrawable(null);
SetNativeControl(editText);
}
}
base.OnElementChanged(e);
}
Where is Resource.Drawable.arrow_down is your arrow image.
You can use tools like ILSpy or dotPeek to look at code inside Xamarin assembly.
I have subclassed a RichTextBox in order to add syntax highlighting, and it works fine when the text is changed manually. However the OnTextChanged event does not fire when the Text is first set in code.
The event code I have is
/// <summary>
/// When text changes keywords are searched for and highlighted
/// </summary>
/// <param name="e"></param>
protected override void OnTextChanged(EventArgs e)
{
if (highlighting)
return;
int currentSelectionStart = this.SelectionStart;
int currentSelectionLength = this.SelectionLength;
base.OnTextChanged(e);
String text = this.Text;
this.Text = "";
this.HighlightSyntax(text);
this.SelectionStart = currentSelectionStart;
this.SelectionLength = currentSelectionLength;
}
How can I get this event to fire when text is set from code e.g. this.structureInFileTextBox.Text = obj.FileStructure;? I've tried overriding the Text property but that makes Visual Studio crash and I have to edit it out of the .cs file before I can open the project again!
I would try this (I only changed this.Text = ""; in base.Text = "";) :
/// <summary>
/// When text changes keywords are searched for and highlighted
/// </summary>
/// <param name="e"></param>
protected override void OnTextChanged(EventArgs e)
{
if (highlighting)
return;
int currentSelectionStart = this.SelectionStart;
int currentSelectionLength = this.SelectionLength;
base.OnTextChanged(e);
String text = this.Text;
base.Text = "";
this.HighlightSyntax(text);
this.SelectionStart = currentSelectionStart;
this.SelectionLength = currentSelectionLength;
}
and override Text property this way :
public new string Text
{
get { return base.Text; }
set
{
if (base.Text != value)
{
base.Text = value;
OnTextChanged(EventArgs.Empty);
}
}
}
anyone know how to raise an event on a ListBox when its redrawn. I'm trying to conditionally mask content in one column but the conditional check seems to be done before the listbox has been drawn and so the mask does not work because there is nothing to mask:
/// <summary>
/// Locks or unlocks the quantity textbox based on 100% flour and activates or deactivate weights
/// </summary>
private void activatePieceQuantity()
{
if (isFlour100Percent())
{
((TextBox)NumberOfItemsTextBox as TextBox).IsEnabled = true;
weightsActive(true);
}
else
{
((TextBox)NumberOfItemsTextBox as TextBox).IsEnabled = false;
weightsActive(false);
}
}
/// <summary>
/// Send controls to search with control name and activate or deactivate flag
/// </summary>
/// <param name="activate"></param>
private void weightsActive(bool activate)
{
int locationInList = 0;
foreach (RecipieIngredient ri in activeRecipie.RecipieIngredients)
{
SearchTree(this.IngredientsListBox.ItemContainerGenerator.ContainerFromIndex(locationInList), "QuanityWeight", activate);
locationInList++;
}
}
/// <summary>
/// Find all weight related objects in the ingredients list and set the visibility accordingly
/// </summary>
/// <param name="targetElement"></param>
/// <param name="flagName">Derived from the Tag of the textbox</param>
/// <param name="enableFlag"></param>
private void SearchTree(DependencyObject targetElement, string flagName, bool enableFlag)
{
if (targetElement == null)
return;
var count = VisualTreeHelper.GetChildrenCount(targetElement);
if (count == 0)
return;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(targetElement, i);
if (child is TextBlock)
{
TextBlock targetItem = (TextBlock)child;
if (targetItem.Name == flagName)
if (enableFlag)
{
((TextBlock)targetItem as TextBlock).Visibility = Visibility.Visible;
return;
}
else
{
((TextBlock)targetItem as TextBlock).Visibility = Visibility.Collapsed;
}
}
else
{
SearchTree(child, flagName, enableFlag);
}
}
}
I got it now, the problem was that the ListBox was not drawn when the SearchTree function was called so there was never any DependencyObject to pass to it.
I solved the problem (somewhat hackish in my opinion) by placing a flag in the code to say that the check had been done and then calling the masking function from a LayoutUpdated event
private void IngredientsListBox_LayoutUpdated(object sender, EventArgs e)
{
if (ingredientsListLoaded)
{
activatePieceQuantity();
ingredientsListLoaded = false;
}
}
I've added a trackbar to menu strip manually because vs 2008 doesn't allow me to do.
However, i can't get the value of trackbar.
Form1.cs:
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.MenuStrip |
ToolStripItemDesignerAvailability.ContextMenuStrip)]
public class TrackBarMenuItem : ToolStripControlHost
{
private TrackBar trackBar;
public TrackBarMenuItem()
: base(new TrackBar())
{
this.trackBar = this.Control as TrackBar;
trackBar.TickFrequency = 1;
trackBar.Maximum = 255;
trackBar.LargeChange = 5;
trackBar.SmallChange = 2;
}
}
Form1.Designer.cs:
private TrackBarMenuItem trackBar1;
//
// trackBar1
//
this.trackBar1.Name = "trackBar1";
this.trackBar1.Size = new System.Drawing.Size(104, 25);
and this is how i need to use it:
private void trackBar1_Scroll(object sender, System.EventArgs e)
{
int valueB = trackBar1.Value;
pictureBox2.Image = Deneme(new Bitmap(pictureBox1.Image),valueB);
}
but i get this error:
Error 1 'goruntuIsleme2.Form1.TrackBarMenuItem' does not contain a
definition for 'Value' and no extension method 'Value' accepting a
first argument of type 'goruntuIsleme2.Form1.TrackBarMenuItem' could
be found (are you missing a using directive or an assembly reference?)
any ideas?
Expose the value of the internal Trackbar object as a property on your new TrackBarMenuItem class:
Value { get { return trackBar.Value; } set { trackBar.Value = value; } }
i am adding the solution i found. someone might need it:
[System.ComponentModel.DesignerCategory("code")]
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ContextMenuStrip | ToolStripItemDesignerAvailability.MenuStrip)]
public partial class ToolStripMenuItem : ToolStripControlHost
{
public ToolStripMenuItem()
: base(CreateControlInstance())
{
}
/// <summary>
/// Create a strongly typed property called TrackBar - handy to prevent casting everywhere.
/// </summary>
public TrackBar TrackBar
{
get
{
return Control as TrackBar;
}
}
/// <summary>
/// Create the actual control, note this is static so it can be called from the
/// constructor.
///
/// </summary>
/// <returns></returns>
private static Control CreateControlInstance()
{
TrackBar t = new TrackBar();
t.AutoSize = false;
t.Height = 16;
t.Maximum = 255;
// Add other initialization code here.
return t;
}
[DefaultValue(0)]
public int Value
{
get { return TrackBar.Value; }
set { TrackBar.Value = value; }
}
/// <summary>
/// Attach to events we want to re-wrap
/// </summary>
/// <param name="control"></param>
protected override void OnSubscribeControlEvents(Control control)
{
base.OnSubscribeControlEvents(control);
TrackBar trackBar = control as TrackBar;
trackBar.ValueChanged += new EventHandler(trackBar_ValueChanged);
}
/// <summary>
/// Detach from events.
/// </summary>
/// <param name="control"></param>
protected override void OnUnsubscribeControlEvents(Control control)
{
base.OnUnsubscribeControlEvents(control);
TrackBar trackBar = control as TrackBar;
trackBar.ValueChanged -= new EventHandler(trackBar_ValueChanged);
}
/// <summary>
/// Routing for event
/// TrackBar.ValueChanged -> ToolStripTrackBar.ValueChanged
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void trackBar_ValueChanged(object sender, EventArgs e)
{
// when the trackbar value changes, fire an event.
if (this.ValueChanged != null)
{
ValueChanged(sender, e);
}
}
// add an event that is subscribable from the designer.
public event EventHandler ValueChanged;
// set other defaults that are interesting
protected override Size DefaultSize
{
get
{
return new Size(200, 16);
}
}
}
if you add this to your code, you will be able to add trackbars as ToolStripMenuItem via Designer.
Does your class TrackBarMenuItem has a property called Value? If not, you have to add it.