WPF Combbox Wildcard Substring Search - c#

I have the following properties set on my combobox-
<ComboBox ItemsSource="{Binding AllLines, Mode=OneWay}" Grid.Column="1" SelectedItem="{Binding SelectedLine}" Margin="4"
Visibility="{Binding ShowLines, Converter={StaticResource BoolToVisible}}" AlternationCount="2"
IsTextSearchEnabled="True" IsEditable="True" TextSearch.TextPath="SearchText" IsTextSearchCaseSensitive="False"
ItemContainerStyle="{StaticResource alternatingWithTriggers}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Margin="2,0,2,0" FontWeight="Bold" Text="{Binding Description}"
Visibility="{Binding Description, Converter={StaticResource NullVisibilityConverter}}"></TextBlock>
<TextBlock Margin="2,2,2,4" Text="{Binding Designator}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Following the suggestion outlined here I added a custom Search property that included the three properties I wanted to search against.
WPF: Changing a ComboBox's ItemTemplate removes the ability to jump down the list as you type. Any way to fix this?
public string SearchText {get { return string.Format("{0} | {1} | {2}", Description, ID, Designator); }}
My question is, can I do a wildcard or substring search on my concatenation of properties?

Found an idea here from which I modeled my solution-
http://jacobmsaylor.com/?p=17
I made some small changes such as listening to the KeyUp instead of the KeyDown and making the filter case-insensitive. I also added a check to make sure that the combo box text (the search text) was not null or empty.
In the code behind-
public SelectRouteSegmentDialog()
{
InitializeComponent();
LineComboBox.Items.Filter += FilterPredicate;
}
private bool FilterPredicate(object obj)
{
Line line = obj as Line;
if (string.IsNullOrEmpty(LineComboBox.Text)) return true;
if (line.SearchText != null)
{
if (line.SearchText.IndexOf(LineComboBox.Text, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
return true;
}
return false;
}
else
{
//if the string is null, return false
return false;
}
}
private void combobox_KeyUp(object sender, KeyEventArgs e)
{
if ((e.Key == Key.Enter) || (e.Key == Key.Tab) || (e.Key == Key.Return))
{
//Formatting options
LineComboBox.Items.Filter = null;
}
else if ((e.Key == Key.Down) || (e.Key == Key.Up))
{
LineComboBox.IsDropDownOpen = true;
}
else
{
LineComboBox.IsDropDownOpen = true;
LineComboBox.Items.Filter += this.FilterPredicate;
}
}
And the xaml I set IsEditable=true, IsTextSearchEnabled=false and TextSearch.TextPath equal to the path I wanted displayed for my selected item (otherwise just the ToString was displayed). I also listend to the key up event-
<ComboBox ItemsSource="{Binding AllLines, Mode=OneWay}" Grid.Column="1" SelectedItem="{Binding SelectedLine}" Margin="4"
Visibility="{Binding ShowLines, Converter={StaticResource BoolToVisible}}" AlternationCount="2"
IsEditable="True" TextSearch.TextPath="SearchText" IsTextSearchEnabled="False"
ItemContainerStyle="{StaticResource alternatingWithTriggers}" x:Name="LineComboBox" KeyUp="combobox_KeyUp">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Margin="2,0,2,0" FontWeight="Bold" Text="{Binding DisplayText}"
Visibility="{Binding Description, Converter={StaticResource NullVisibilityConverter}}"></TextBlock>
<TextBlock Margin="2,2,2,4" Text="{Binding Designator}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

My question is, can I do a wildcard or substring search on my concatenation of properties?
Not using the built-in TextSearch mechanism; it's a prefix match only. You can specify the text directly, or provide the path to the property containing the text (as you have done), but you cannot change the matching behavior.
You will have to implement your own text search mechanism to get the kind of behavior you want. Try exploring the TextSearch source code for implementation ideas.

Related

TextBlock stop reacting to data binding after changing Inlines

My goal is having TextBox over TextBlock which upon finished typing changes its Inlines in order to colorize certain keywords.
My control xaml:
<Grid>
<TextBlock Text="{Binding Text, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Foreground="AliceBlue"
FontFamily="Consolas"
Name="MyTextBlock"/>
<TextBox AcceptsTab="True"
AcceptsReturn="True"
TextWrapping="WrapWithOverflow"
Foreground="Transparent"
Background="Transparent"
Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="OnTextChanged"
PreviewKeyDown="OnPreviewKeyDown"
Name="MyTextBox"/>
</Grid>
Part of code that is problematic:
private void HandleFinishedTypingEvent(object sender, EventArgs e)
{
//Timer is being used for end typing detection
(sender as Timer).Stop();
Dispatcher.Invoke(() =>
{
var inlines = MyTextBlock.Inlines;
inlines.Clear();
Run run;
foreach (string word in Text.Split(' '))
{
run = new Run(word + " ");
if (word == "keyword")
{
run.Foreground = Brushes.Lime;
inlines.Add(run);
}
else
{
run.Foreground = Brushes.AliceBlue;
inlines.Add(run);
}
}
});
}
The code itself work but after that TextBlock doesn't update by property change, only when code updating Inlines runs.

How to change TextBlock Text Binding in C#

I'm working in huge application and I have one small problem
My Application has two languages (Arabic / English).
I have ComboBox And I would like to change the display content according to the language.
This is my ComboBox XAML:
<ComboBox x:Name="cmbCustomerGroup" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5"
Margin="2" SelectedValuePath="CustomerGroupId" Validation.Error="Validation_Error"
SelectedValue="{Binding Path=CustomerGroupId, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True}">
<!--<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>-->
</ComboBox>
This is my method:
private void FillCustomerGroups()
{
var oClsCustomers = new ClsCustomerGroups();
var lstCustGrps = oClsCustomers.GetData();
cmbCustomerGroup.ItemsSource = lstCustGrps.ToList<TbCustomerGroups>();
cmbCustomerGroup.DisplayMemberPath = Helper.CurrLang == Helper.SystemLanguage.Arabic ? "CustomerGroupAName" : "CustomerGroupEName";
cmbCustomerGroup.SelectedValuePath = "CustomerGroupId";
}
I got this result:
This is my database:
This usually occurs when DisplayMemberPath is set wrong, or bindable property is not a string and has no overriden ToString() method.
Try add new property to your TbCustomerGroups, for example CurrentGroupName like this
public string CurrentGroupName => Helper.CurrLang == Helper.SystemLanguage.Arabic ? CustomerGroupAName : CustomerGroupEName;
Then set cmbCustomerGroup.DisplayMemberPath = "CurrentGroupName"
Also check that CustomerGroupAName and CustomerGroupEName are strings or have ToString() method
UPDATE
Also don't use <ComboBox.ItemTemplate> if you use DisplayMemberPath

How to get text from Combo box c# Wpf?

Whenever I'm trying to get text from combo box it extracts data like System.Windows.Controls.ComboBoxItem: Abc
How can I get only "Abc" ? I mean to say only value not entire stack trace.
my code seems like:-
XAML:-
<StackPanel Orientation="Horizontal" Width="auto" HorizontalAlignment="Center" Margin="0,10,0,0">
<TextBlock HorizontalAlignment="Left" FontFamily="/Vegomart;component/Images/#My type of font" Text="User Type:- " FontSize="18" Foreground="Black"/>
<ComboBox x:Name="userType" HorizontalAlignment="Right" FontFamily="/Vegomart;component/Images/#My type of font" Width="170" FontSize="18" Foreground="Black" Margin="40,0,0,0" >
<ComboBoxItem> Abc</ComboBoxItem>
</ComboBox>
</StackPanel>
C#:-
string value = userType.SelectedItem.ToString();
System.Diagnostics.Debug.WriteLine(value);
Your effort will be appreciated :).
Thanks,
<ComboBox x:Name="userType" SelectionChanged="userType_SelectionChanged">
<ComboBoxItem Content="Abc"/>
<ComboBoxItem>Bcd</ComboBoxItem>
</ComboBox>
Then in code behind:
private void userType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var comboBox = sender as ComboBox;
if (comboBox != null)
{
var comboBoxItem = comboBox.SelectedItem as ComboBoxItem;
if (comboBoxItem != null)
{
var content = comboBoxItem.Content;
System.Diagnostics.Debug.WriteLine(content);
}
}
}
<ComboBoxItem> Abc</ComboBoxItem> sets the Content to Abc, so you would need to cast your SelectedItem to ComboBoxItem and get that property.
(That the XAML sets the content can be seem in the base class ContentControl which has a ContentPropertyAttribute that defines which property to set.)
This should return the text of the selected item in the ComboBox.
string value = userType.Text.ToString();
You can get the content of the item:
ComboBoxItem item = (ComboBoxItem)userType.SelectedItem;
string value = (string)item.Content;
System.Diagnostics.Debug.WriteLine(value);

show/hide control textbox based on combobox selected WPF

I have a WPF/MVVM project in C #/FrameWork 4.0
In my view I have two ControlBox "NoRSAC" and "LieuRSAC"
<View:StateControlTextBox
x:Name="NoRSAC"
ReadOnly="{Binding IsReadOnly}"
ViewModelDataType="UtilisateurSaisieViewModel"
TableDataType="TUtilisateurDataTable"
Tag="{DynamicResource TELEPHONE}"
Text="{Binding UserVM.No_RSAC, Mode=TwoWay}" Margin="0" Canvas.Top="140" Width="185" VerticalAlignment="Stretch" />
<View:StateControlTextBox
x:Name="LieuRSAC"
ReadOnly="{Binding IsReadOnly}"
ViewModelDataType="UtilisateurSaisieViewModel"
TableDataType="TUtilisateurDataTable"
Tag="{DynamicResource TELEPHONE}"
Text="{Binding UserVM.Lieu_RSAC, Mode=TwoWay}" Margin="0" Canvas.Top="140" Width="185" VerticalAlignment="Stretch"/>
</Canvas>
And ControlComboBox "cmbFonction"
<View:StateControlComboBox
x:Name="cmbFonction"
ReadOnlyControlState="Disabled"
IsReadOnly="{Binding IsReadOnly}"
ViewModelDataType="UtilisateurSaisieViewModel"
TableDataType="TUtilisateurDataTable"
ItemsSource="{Binding ListeFonctions}"
SelectedValue="{Binding UserVM.Fonction, Mode=TwoWay}" Width="303" Margin="0" HorizontalAlignment="Left" Canvas.Left="97" Canvas.Top="108" />
I want to view the ControlBox "NoRSAC" and "LieuRSAC" when I select a particular valeure in the ComboBox "cmbFonction" and hide when it's another selected value
Thank you for your help
In the set method of the property Fonction, you can check the value and update another property that you should introduce in your view model and that is of type System.Windows.Visibility. In the following example, I call this property TextBoxVisibility:
public class UserVM : INotifyPropertyChanged
{
private Visibility _textBoxVisibility;
public Visibility TextBoxVisibility
{
get { return _textBoxVisibility; }
set
{
_textBoxVisibility = value;
OnPropertyChanged();
}
}
public string Fonction
{
get { return _fonction; }
set
{
_fonction = value;
OnPropertyChanged();
if (value == "Value A")
TextBoxVisibility = Visibility.Hidden;
else
TextBoxVisibility = Visibility.Visible;
}
}
// Other members omitted for sake of simplicity.
}
Please note that you need to implement INotifyPropertyChanged (directly or indirectly) so that the changes of the property values are forwarded to the bindings that can in turn update the dependency properties of the controls in your view.
Thus you must not forget to add an additional binding to all of your text boxes in your view. Here is an example for that, the important part is the binding on Visibility:
<View:StateControlTextBox
x:Name="NoRSAC"
ReadOnly="{Binding IsReadOnly}"
ViewModelDataType="UtilisateurSaisieViewModel"
TableDataType="TUtilisateurDataTable"
Tag="{DynamicResource TELEPHONE}"
Visibility="{Binding UserVM.TextBoxVisibility}"
Text="{Binding UserVM.No_RSAC, Mode=TwoWay}" Margin="0" Canvas.Top="140" Width="185" VerticalAlignment="Stretch" />

Bind IsEnabled property to Boolean in WPF

I have a TextBox which needs to be enabled / disabled programmatically. I want to achieve this using a binding to a Boolean. Here is the TextBox XAML:
<TextBox Height="424" HorizontalAlignment="Left"
Margin="179,57,0,0" Name="textBox2"
VerticalAlignment="Top" Width="777"
TextWrapping="WrapWithOverflow"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
AcceptsReturn="True" AcceptsTab="True"
Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=TextBoxEnabled}"/>
Notice the Text property is bound as well; it is fully functional, which makes me think it is not a DataContext issue.
However, when I call this code:
private Boolean _textbox_enabled;
public Boolean Textbox_Enabled
{
get { return _textbox_enabled; }
set
{
OnPropertyChanged("TextBoxEnabled");
}
}
It does not work. To give further information, the TextBox_Enabled property is changed by this method:
public void DisabledTextBox()
{
this.Textbox_Enabled = false;
}
..which is called when a key combination is pressed.
Here are your little typos!
private Boolean _textbox_enabled;
public Boolean TextboxEnabled // here, underscore typo
{
get { return _textbox_enabled; }
set
{
_textbox_enabled = value; // You miss this line, could be ok to do an equality check here to. :)
OnPropertyChanged("TextboxEnabled"); //
}
}
Another thing for your xaml to update the text to the vm/datacontext
Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding TextBoxEnabled}"/>

Categories