Is this a bug in DotNet 4 WPF Spell Checking? - c#

I have:
Created a Windows forms project.
Created a UserControl to hold a WPF TextBox.
Added a CustomDictionary to the TextBox's SpellCheck.
Added the UserControl to my Windows Form.
XAML is used to add the WPF textbox to the user control:
<UserControl x:Class="TestElementHost.SpellBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="248" d:DesignWidth="250">
<Grid>
<TextBox Name="txtWPF" />
</Grid>
</UserControl>
Here is the form code (buttons added in the VS designer file):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestElementHost
{
public partial class Form1 : Form
{
private System.Windows.Forms.Integration.ElementHost elementHost1;
private SpellBox spellBox1;
public Form1()
{
InitializeComponent();
this.elementHost1 = new System.Windows.Forms.Integration.ElementHost();
this.spellBox1 = new TestElementHost.SpellBox();
this.elementHost1.Location = new System.Drawing.Point(27, 12);
this.elementHost1.Name = "elementHost1";
this.elementHost1.Size = new System.Drawing.Size(269, 296);
this.elementHost1.TabIndex = 0;
this.elementHost1.Text = "elementHost1";
this.elementHost1.Child = this.spellBox1;
this.Controls.Add(this.elementHost1);
}
private void Form1_Load(object sender, EventArgs e)
{
spellBox1.txtWPF.SpellCheck.IsEnabled = true;
spellBox1.txtWPF.SpellCheck.CustomDictionaries.Add(new Uri(Application.StartupPath + #"\MyDictionary.lex"));
}
private void button1_Click(object sender, EventArgs e)
{
spellBox1.txtWPF.Text = "my bbad word."; // bbad is in the CustomDictionary
}
private void button2_Click(object sender, EventArgs e)
{
spellBox1.txtWPF.IsEnabled = false;
spellBox1.txtWPF.IsEnabled = true;
// spellBox1.txtWPF.SpellCheck.IsEnabled = false;
// spellBox1.txtWPF.SpellCheck.IsEnabled = true;
}
}
}
This works quite happily and words in the CustomDictionary are ignored, until I try changing the IsEnabled, IsReadOnly or the Visibility property. For example, set IsReadOnly to true then straight back to false again and suddenly words that are in the customdictionary are redlined.
The way I am getting round this is to set SpellCheck.IsEnabled to false then back to true on consecutive lines when I need to allow users to edit text in the control. This seems to bring the customdictionary back into play.
Has anyone else had this problem? Is this a bug or have I missed something?

It looks like a "feature" (thanks for verifying this Joachim):
If you are using the custom dictionary, then change the visbility, enabled or read only attributes of the WPF textbox or the user control, the spell checker ignores the custom dictionary.
To get round this, disable then re-enable spell checking.
This applies to dot net runtime v4.0.30319

Related

Custom ComboBox: prevent designer from adding to Items

I have a custom combobox control that is supposed to show a list of webcams available.
The code is fairly tiny.
using System;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using DirectShowLib;
namespace CameraSelectionCB
{
public partial class CameraComboBox : ComboBox
{
protected BindingList<string> Names;
protected DsDevice[] Devices;
public CameraComboBox()
{
InitializeComponent();
Devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
Names = new BindingList<string>(Devices.Select(d => d.Name).ToList());
this.DataSource = Names;
this.DropDownStyle = ComboBoxStyle.DropDownList;
}
}
}
However, I ran into a couple of bugs.
First, whenever I place an instance of this combobox, designer generates the following code:
this.cameraComboBox1.DataSource = ((object)(resources.GetObject("cameraComboBox1.DataSource")));
this.cameraComboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cameraComboBox1.Items.AddRange(new object[] {
"HP Webcam"});
Which results in an exception during runtime, since Items should not be modified when DataSource is set. This happens even if I don't touch Items property in the designer.
"HP Webcam" is the only camera present on my computer at the time.
How can I suppress this behaviour?
When you drop your control on a form the constructor code and any loading code will run. Any code in there that changes a property value will be executed in designtime and therefore will be written in the designer.cs of the form you dropped your control on.
When programming controls you should always keep that in mind.
I solved this by adding a property that I can use to check if the code executed in designtime or runtime.
protected bool IsInDesignMode
{
get { return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; }
}
protected BindingList<string> Names;
protected DsDevice[] Devices;
public CameraComboBox()
{
InitializeComponent();
if (InDesignMode == false)
{
// only do this at runtime, never at designtime...
Devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
Names = new BindingList<string>(Devices.Select(d => d.Name).ToList());
this.DataSource = Names;
}
this.DropDownStyle = ComboBoxStyle.DropDownList;
}
Now the binding will only happen at runtime
Dont forget to remove the generated code in the Designer.cs file when you try this
The problem is that the binding in constructor is being run by the designer. You could try moving it to the Initialise or Loaded events

Selecting A Series Of Text Boxes

I have a series(10) of selectable TextBoxes. I need to be able to click on one of them and select all the text boxes on which the mouse is moved until the click is released.
I used the following code but I am unable to hit the MouseMove on the other TextBoxes. It always hits the TextBox on which the Click was made.
class SelectableTextBox: TextBox
{
public Boolean IsSelected { get; protected set; }
public void select(Boolean value)
{
this.IsSelected = value;
if (value)
{
this.Background = System.Windows.Media.Brushes.Aqua;
}
else
{
this.Background = System.Windows.Media.Brushes.White;
}
}
}
private void onPreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
SelectableTextBox textBox = (SelectableTextBox)sender;
this.SelectionStartedRight = !textBox.IsSelected;
textBox.select(!textBox.IsSelected);
}
private void onPreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
SelectableTextBox textBox = (SelectableTextBox)sender;
if (this.SelectionStartedRight)
{
textBox.select(true);
}
}
private void onPreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
SelectableTextBox textBox = (SelectableTextBox)sender;
this.SelectionStartedRight = false;
}
Try using MouseEnter event instead of MouseMove. Attach MouseEnter to your selectable textboxes. That would ensure that only they trigger the desired event handler and its code.
If you decide to stay with the global handler, be careful when you convert sender to a specific control type. You need to account for those times when it's not the "expected" control:
SelectableTextBox textBox = sender as SelectableTextBox;
if (textBox != null)
{
// The rest of the code here...
}
select is a Linq keyword, so you might want to rename that method to avoid any conflicts down the road. While I don't think it'd be causing any issues, I would change it.
You don't have to follow this convention, but in C# its customary to use an uppercase for the first letter of a method. Also note that the default access modifier for a class is internal... just want to make sure you're aware of that, as you continue your development.
Your last method, onPreviewMouseLeftButtonUp(...) has the following code in it:
SelectableTextBox textBox = (SelectableTextBox)sender;
Not only is it unsafe, as I've described above, but it also does absolutely nothing.
Lastly... and this is just me, I would probably move the code that handles changing the state of a selectable textbox (selected or not selected) into its class, since it belongs there. Why should anything else be in charge of how it handles its state. Keep things where they belong and you'll have a much easier time testing, debugging and maintaining your code. Don't fall into the "I'll refactor it later" trap... it'll rarely happen.
Here's my crude example. I let the class handle its MouseEnter event and simply check if the Mouse.LeftButton is down at that time. You would have to expand on it, but it should be a solid start:
Made some edits per OP's requests in the comments.
Preview:
XAML:
<Window x:Class="SelectableTextBoxes.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SelectableTextBoxes"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
<local:SelectableTextBox Height="20" Width="100" Margin="10"/>
</StackPanel>
</Window>
C# (Pardon me for putting the SelectableTextBox into the same file...):
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace SelectableTextBoxes
{
// Move this class into its own file (it's here for prototyping).
public class SelectableTextBox : TextBox
{
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
// If the value changes, sets new color.
SetSelectionColor();
}
}
}
public SelectableTextBox()
{
// For handling an initial click if it happens in the textbox.
PreviewMouseDown += SelectableTextBox_PreviewMouseDown;
// For handling selection when mouse enters the textbox
// and left mouse button is down.
MouseEnter += SelectableTextBox_MouseEnter;
// To handle mouse capture (release it).
GotMouseCapture += SelectableTextBox_GotMouseCapture;
}
// Handles the mouse down event within the textbox.
void SelectableTextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (!IsSelected)
{
IsSelected = true;
}
// If one of the Shift keys is down, return, since
// we don't want to deselect others.
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
return;
}
// This part makes a poor assumption that the parent is
// always going to be a Panel... expand on this code to
// cover other types that may contain more than one element.
var parent = VisualTreeHelper.GetParent(this) as Panel;
if (parent != null)
{
foreach (var child in parent.Children)
{
// If a child is not of a correct type, it'll be null.
var tbx = child as SelectableTextBox;
// This is where we check to see if it's null or this instance.
if (tbx != null && tbx != this)
{
tbx.IsSelected = false;
}
}
}
}
// When textbox receives focus, this event fires... we need to release
// the mouse to continue selection.
void SelectableTextBox_GotMouseCapture(object sender, MouseEventArgs e)
{
ReleaseMouseCapture();
}
// Sets selection state to true if the left mouse button is
// down while entering.
void SelectableTextBox_MouseEnter(object sender, MouseEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
IsSelected = true;
}
}
// Sets the background color based on selection state.
private void SetSelectionColor()
{
if (IsSelected)
{
Background = Brushes.LightCyan;
}
else
{
Background = Brushes.White;
}
}
}
// Window code... should be on its own, but I placed the two
// classes together while prototyping.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

Disable/enable a page on a popup being shown/hidden in wp8

I am using a windows phone user control to show a popup. I used this because My app may be calling for a log in # several points(not if already logged in). I was able to display the popup(used a class). This is my first time exposure to mobile apps. What I need is to disable the page from which the popup is called and enable it once we are logged in or cancelled the popup. Please find my code below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Controls.Primitives;
namespace Project1.Utilies
{
class TALogin
{
public void display_cspopup()
{
Popup popup = new Popup();
popup.Height = 300;
popup.Width = 400;
popup.VerticalOffset = 200;
Pages.PopupController control = new Pages.PopupController();
popup.Child = control;
popup.IsOpen = true;
control.popuplgnbtn.Click += (s, args) =>
{
popup.IsOpen = false;
};
control.popupcnclbtn.Click += (s, args) =>
{
popup.IsOpen = false;
};
}
}
}
AS you may have guessed, PopupController is the controller created for Popup UI(xaml file).
Thanks,
Akhil
what you can do is have two secondary Grids in your Primary Grid and set the visibility to visible or collapsed as per you require!!
your xaml should look somewhat like this:
<Grid x:name="ParentGrid">
<Grid x:name="ChildGrid1">
<!-- your work -->
</Grid>
<Grid x:name="ChildGrid2">
<!-- your work -->
</Grid>
</Grid>
assume you have a button in your grid, on its click event you can collapse any of the grids in this manner!!
//in click event of the button:
ChildGrid1.Visibility=Visibility.Collapsed;
Hope this helps!! :)

Create a custom control in Corel Draw X6 using only VSTA

I am in the process of creating a plugin (or addin) for CorelDraw X6 using VSTA (Visual Studio for Applications) because I like C# and .NET library. I would like to have a button in CorelDraw toolbar, so when a user clicks this button some action happens, for example, a form is showed. For that I use predefined solution VSTAGlobal, that is there for me when I start CorelDraw. Unfortunately, there is NO official documentation (WTF!!!!!) for VSTA in CorelDraw, instead we have VBA (Visual Basic for Applications) documentation and CorelDraw Object Model. I googled a lot and found a few links: some forum post and YouTube video tutorial. The problem is, both guys there create their CustomControl (a buton for example) and simply build it as *.dll and then use VBA script to add the CustomControl to CorelDraw toolbar like this
Sub addLineWidthControl()
Call FrameWork.CommandBars("Standard").Controls. '
AddCustomControl("MyNameSpace.MyCustomControlClass", '
"MyCustomControlAssembly.dll")
End Sub
So, my question is: is there any way to do this using only VSTA?
Additional info:
For example, in the default solution VSTAGlobal there is a Main class with [CgsAddInModule] attribute:
[CgsAddInModule]
public partial class Main
{
private Corel.Interop.VGCore.Application app;
// some other code here...
}
This class has a constructor (note, default and provided by CorelDraw):
[CgsAddInConstructor]
public Main(object _app)
// this constructor probably gets an instance
// of CorelDraw application object.
{
app = _app as Corel.Interop.VGCore.Application;
// will it work if I add some code here?
}
Maybe this is the place where I should add something like this:
app.FrameWork.CommandBars["Standard"]
.Controls.AddCustomControl("MyCustomControlClass");
I did some experiments with this last line of code. I obtained that the Count of Controls is increasing, but still MyCustomControl does not show up in the toolbar.
There is a way to use only C# (I tested this in Corel X8 but it should work in any version that has VSTA). It is a 2 part process though. First you will need to open Macro Manager in Corel and edit the VSTAGlobal solution. For example, if you want to add a button and a slider, add this method:
[CgsAddInMacro]
public void Add()
{
string controlAssembly = #"C:\VSTS\ScratchProjects\CoreDrawPoC\CoreDrawPoC\bin\Debug\CoreDrawPoC.dll";
var mySlider = app.FrameWork.CommandBars["Standard"].Controls.AddCustomControl("CoreDrawPoC.MySlider", controlAssembly);
mySlider.Caption = "Border Sizing Slider Caption";
mySlider.ToolTipText = "Border Sizing Slider Tooltip";
var myButton = app.FrameWork.CommandBars["Standard"].Controls.AddCustomControl("CoreDrawPoC.ButtonSample", controlAssembly);
myButton.Caption = "Rectanlge Selector";
mySlider.ToolTipText = "Rectanlge Selector Tooltip";
}
Once you add this code, you will need to add a .dll for a solution to the folder listed above. Open Visual Studio 2015 and create a new project (mine was named CoreDrawPoC). It needs to be a WPF User Control Library project. Create 2 .xaml files with. First will be the slider:
<UserControl x:Class="CoreDrawPoC.MySlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CoreDrawPoC"
mc:Ignorable="d" >
<Slider x:Name="mySlider" Width="100" Minimum=".5" Maximum="10" TickFrequency=".5" IsSnapToTickEnabled="True" ValueChanged="mySlider_ValueChanged"/>
</UserControl>
Code behind is:
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CoreDrawPoC
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class MySlider : UserControl
{
Corel.Interop.VGCore.Application appDraw = null;
public MySlider()
{
InitializeComponent();
}
public MySlider(object app)
{
InitializeComponent();
appDraw = (Corel.Interop.VGCore.Application)app;
}
private void mySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (appDraw != null && appDraw.ActiveDocument != null && appDraw.ActiveShape != null)
{
double width = appDraw.ConvertUnits((double)e.NewValue, Corel.Interop.VGCore.cdrUnit.cdrPoint, Corel.Interop.VGCore.cdrUnit.cdrInch);
appDraw.ActiveSelectionRange.SetOutlineProperties(width);
}
}
}
}
Then create the button:
<UserControl x:Class="CoreDrawPoC.ButtonSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CoreDrawPoC"
mc:Ignorable="d">
<Button x:Name="buttonSample" Click="buttonSample_Click" Width="24" Height="24" >
<Button.Template>
<ControlTemplate>
<Image Source="C:\CorelIcons\Two.bmp"/>
</ControlTemplate>
</Button.Template>
</Button>
</UserControl>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CoreDrawPoC
{
/// <summary>
/// Interaction logic for ButtonSample.xaml
/// </summary>
public partial class ButtonSample : UserControl
{
Corel.Interop.VGCore.Application appDraw = null;
public ButtonSample()
{
InitializeComponent();
}
public ButtonSample(object app)
{
InitializeComponent();
appDraw = (Corel.Interop.VGCore.Application)app;
}
private void buttonSample_Click(object sender, RoutedEventArgs e)
{
SelectOfType("rectangle");
}
private void SelectOfType(string strType)
{
string strQuery = null;
Corel.Interop.VGCore.ShapeRange srGroup = default(Corel.Interop.VGCore.ShapeRange);
Corel.Interop.VGCore.ShapeRange srTopOnly = default(Corel.Interop.VGCore.ShapeRange);
strQuery = "#type='" + strType + "'";
srGroup = appDraw.ActivePage.Shapes.FindShapes("", 0, true, strQuery);
srTopOnly = appDraw.ActivePage.Shapes.FindShapes("", 0, false, strQuery);
srTopOnly.CreateSelection();
appDraw.ActivePage.Shapes.FindShapes("", 0, false, strQuery).CreateSelection();
//if (srTopOnly.Count == srGroup.Count)
//{
// lblWarning.Visibility = System.Windows.Visibility.Hidden;
//}
//else
//{
// lblWarning.Visibility = System.Windows.Visibility.Visible;
//}
}
}
}
Once that is done, you will want to compile the code. Also, you will want to create the image C:\CorelIcons\Two.bmp. It is just a 24x24 bitmap that looks however you want it to look. Then compile the project. You will need to this will CorelDraw closed.
Once it compiles successfully, you will want to go and run your VSTA macro to add the button and slider. This macro will only need to be run 1 time! After than, it will connect directly to the code in your dll. If you change anything in the dll and update it while Corel is closed, it changes it. This includes the images.
Finally, I learned how to do this from 2 blog posts and I only changed it to add a button to the Standard command bar and to use purely C#. Those posts are:
https://forum.oberonplace.com/blog.php?b=165
https://forum.oberonplace.com/blog.php?b=166

ComboBox Up/Down arrow keys issue after Items is repopulated

I am creating a custom ComboBox control with Google Search results implementation but I am running into some problem using the arrow keys.
Details of the problem
Please watch this video as I demonstrate the problem with UP and DOWN arrow keys and take a look on the output panel as well.
http://screencast.com/t/DFkmlDKR
In the video, I tried searching for "a" (just a test) and returns the Google search results that starts with "a" then I am pressing the DOWN and UP arrow keys. In the output panel, it shows the highlighted item as I press these keys.
Then I typed the next letter "l". Now If you noticed on the output panel, the selection is now "null" but I'm still pressing the UP & DOWN arrow keys.
And when you hover on the item again using the mouse pointer, it will start working again.
I am stuck with this problem for days and haven't figured out the solution.
I have uploaded the test version of this control so you can play with it as well. Here it is GoogleSuggestionComboBox
My goal here is to make the UP & DOWN arrow keys work all the time.
In this section of the code
I tried adding
SelectedIndex = 0;
after the ForEach statement so everytime the collection is repopulated with the new results, it will select the first result. Unfortunately, it did not work.
You can download the test code so you can play and test the problem. http://sdrv.ms/1eWV3Bc and here's the code for the ComboBox as well.
using GoogleSuggestionComboBox.Model;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace GoogleSuggestionComboBox
{
public class ComboBoxExC : ComboBox
{
GoogleSuggest google;
TextBox textbox;
string _text = string.Empty;
string _last_text = string.Empty;
public ComboBoxExC()
{
if (DesignerProperties.GetIsInDesignMode(this))
{
}
else
{
this.Loaded += ComboBoxExC_Loaded;
google = new GoogleSuggest();
google.OnGoogleSuggestAvailable += google_OnGoogleSuggestAvailable;
// since we have OnSelectionChanged "disabled"
// we need a way to know if the item in ComboBox is selected using mouse
EventManager.RegisterClassHandler(typeof(ComboBoxItem), ComboBoxItem.MouseDownEvent, new MouseButtonEventHandler(OnItemMouseDown));
}
}
void ComboBoxExC_Loaded(object sender, RoutedEventArgs e)
{
this.textbox = (TextBox)Template.FindName("PART_EditableTextBox", this);
}
private void OnItemMouseDown(object sender, MouseButtonEventArgs e)
{
var comboBoxItem = sender as ComboBoxItem;
if (comboBoxItem != null && comboBoxItem.IsHighlighted)
{
Model_SuggestedQueries m = (Model_SuggestedQueries)comboBoxItem.Content;
Go(m.Query);
}
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
// don't do anything so the .Text value won't change.
//base.OnSelectionChanged(e);
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
this.IsDropDownOpen = true;
base.OnPreviewKeyDown(e);
d("key: " + e.Key.ToString());
if (this.SelectedItem != null)
{
Model_SuggestedQueries m = (Model_SuggestedQueries)this.SelectedItem;
d("selected: " + m.Query);
}
else
{
d("null");
}
}
protected override void OnPreviewKeyUp(KeyEventArgs e)
{
base.OnPreviewKeyUp(e);
if (e.Key == Key.Enter)
{
if (this.SelectedItem == null)
{
Go(this.Text);
}
else
{
Model_SuggestedQueries m = (Model_SuggestedQueries)this.SelectedItem;
Go(m.Query);
}
}
else
{
if (this.Text != this._last_text)
{
google.LookForSuggestion(this.Text);
this._last_text = this.Text;
}
}
}
void google_OnGoogleSuggestAvailable(object sender, List<Model.Model_SuggestedQueries> suggestions)
{
this.Items.Clear();
suggestions.ForEach((a) =>
{
this.Items.Add(a);
});
}
void d(object a)
{
Debug.WriteLine(">>> " + a);
}
void Go(string query)
{
Process.Start("https://www.google.com.ph/search?q=" + query);
// clear suggestions
this.Items.Clear();
}
}
}
MainWindow.xaml
<Window x:Class="GoogleSuggestionComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:GoogleSuggestionComboBox"
Title="MainWindow" Height="133" Width="261" WindowStartupLocation="CenterScreen"
>
<Grid>
<StackPanel Margin="10">
<TextBlock Text="Search" />
<l:ComboBoxExC
IsEditable="True"
IsTextSearchEnabled="False"
TextSearch.TextPath="Query"
>
<l:ComboBoxExC.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Query}" />
</DataTemplate>
</l:ComboBoxExC.ItemTemplate>
</l:ComboBoxExC>
</StackPanel>
</Grid>
</Window>
Thank you,
Jayson
This is a pretty old question but I ran into about the same problem. The main issue for me was after selecting an item or clearing selection (setting it to -1) I could not go through the items with the arrow keys anymore until I hovered over them with my mouse.
After some days of struggling I found a fix for this:
KeyboardNavigation.SetDirectionalNavigation( this, KeyboardNavigationMode.Cycle );
this is the combobox, and this line is in the constructor of a sub classed combobox.
I don't know the exact issue, but here is a suggestion:
Don't subclass the ComboBox - you don't need to.
Just drop one on the MainForm, and then work with it from the code behind - it is much easier to work with it like that. You only need to subclass if you need to change the way a combo-box works which is not typical.
I tried downloading the test project, but it is not a zip file - it is a .7z which I could not open.
Also, you main form is a Window. That may not be an issue, but try creating a new project and just working with the Main form the project gives you. There is some wiring up that is done in the App that calls the MainForm that will catch exceptions etc, and that may give you more data as to what the issue is.
Greg

Categories