Prevent list box automatically selecting first item when binding changes - c#

I have a setup like this:
ViewModel snippet:
private ObservableCollection<Field> _Fields;
public ObservableCollection<Field> Fields
{
get
{
return _Fields;
}
set
{
NotifyPropertyChanged(ref _Fields, value, "Fields");
}
}
private Field _SelectedField;
public Field SelectedField
{
get
{
return _SelectedField;
}
set
{
NotifyPropertyChanged(ref _SelectedField, value, "SelectedField");
}
}
XAML:
<ListBox x:Name="FieldList" ItemsSource="{Binding Fields}" SelectedValue="{Binding SelectedField}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I update the field collection quite frequently, like this:
List<Field> myFieldList = myDataSource.GetFields();
Fields = new ObservableCollection<Field>(myFieldList);
When I do this, the list box automatically defaults to selecting the first item. I would like it to not select anything by default (e.g. SelectedIndex = -1 or SelectedValue = null). How can I achieve this?

I tried it but could not reproduce it.
If you already have SelectedField in your VM try to set it tu null just after you update Fields.
You could also try to use an Action/Trigger to set the SelectedIndex to -1 like this
<ListBox x:Name="FieldList" ItemsSource="{Binding Fields}" SelectedValue="{Binding SelectedField}">
<i:Interaction.Triggers>
<ei:PropertyChangedTrigger Binding="{Binding Fields}">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=FieldList}" PropertyName="SelectedIndex" Value="-1"/>
</ei:PropertyChangedTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But actually it is not the best way to reset the selection.

After binding or loading the list, set
listbox1.SelectedIndex=-1;

Related

Problem with Combobox binding to ObservableCollection in MVVM

I have a little problem and I don't know how to fix it.
In my View I have a combobox, that should be able to display the property "Name" of the ObservableCollection "Phases". I already tried to show a single "Name-property" without a Datatemplate and it worked. I think I messed something up with the binding in the DataTemplate. What is wrong? Can you help me?
Here is my View:
<ComboBox ItemsSource="{Binding Phases}"
SelectedItem=""
Width="100" HorizontalAlignment="Left"
Margin="50,20">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Here my ObservableCollection:
public ObservableCollection<PhaseViewModel> Phases
{
get;
}
And here the property inside Phases:
public string Name
{
get { return myName; }
set { myName = value;}
}

Multiple checkbox in list and is check in wpf

I've got a question, I have a list of checkbox in combobox box and it looks like this:
<StackPanel Orientation="Vertical" DataContext="{Binding CandidateEntity}">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding DataContext.SkillSetEntities, ElementName=CrudCandidate }"
IsEditable="True" IsReadOnly="True" Text="Umiejętności">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</StackPanel>
Now I also have a collection of skillset objects in binded item source (CandidateEntity.SkillSets), now how can I check those checkboxes that are in my collection of skillset objects?
I want to create a edition for CandidateEntity object in form and part of that edition is list of skillset that is represented in combobox.
EDIT:
I have solved problem by adding to skillset model prop:
private bool _isSelected = false;
[NotMapped]
public bool IsSelected
{
get
{
return this._isSelected;
}
set
{
_isSelected = value;
}
}
And then in view model:
private List<SkillSet> GetSkillSets()
{
var skillsetList = this._catalog.SkillSets.ToList();
var candidateSkillsetList = this.CandidateEntity.SkillSets.ToList();
foreach (SkillSet skillset in skillsetList)
{
foreach (SkillSet candidateSkillset in candidateSkillsetList)
{
if (skillset.id == candidateSkillset.id)
{
skillset.IsSelected = true;
}
}
}
return skillsetList;
}
and in checkbox in wpf:
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}"/>
BUT I am pretty sure there must be easier way to handle that, is there?

How to set the focus in a TextBox of a ListView item?

On a UWP app (Windows 10), I am displaying a list of records in a ListView.
When I click on an item, its StackPanel is displayed (using INotifyPropertyChanged).
In the StackPanel, there is a TextBox with some data populated via binding.
I would like that the TextBox automatically receives the focus whenever the StackPanel becomes visible, but I can't find which property or event to use, and how to trigger a textBox.Focus().
Thanks for your feedback on this !
The DataTemplate:
<DataTemplate x:Key="templateList">
<StackPanel>
...
<StackPanel Visibility="{Binding IsSelected}">
<TextBox x:Name="textBox"
Text="{Binding Title, Mode=TwoWay}"/>
...
</StackPanel>
</StackPanel>
</DataTemplate>
...
The ListView:
<ListView x:Name="listView"
ItemsSource="{Binding mylist}"
ItemTemplate="{StaticResource templateList}"/>
I can suggest use Behaviors for this case. As I noticed, you use Visibility type for IsSelected property. It means that we can use DataTriggerBehavior and create our SetupFocusAction which implement IAction
public class SetupFocusAction : DependencyObject, IAction
{
public Control TargetObject
{
get { return (Control)GetValue(TargetObjectProperty); }
set { SetValue(TargetObjectProperty, value); }
}
public static readonly DependencyProperty TargetObjectProperty =
DependencyProperty.Register("TargetObject", typeof(Control), typeof(SetupFocusAction), new PropertyMetadata(0));
public object Execute(object sender, object parameter)
{
return TargetObject?.Focus(FocusState.Programmatic);
}
}
After that we can use this action in XAML:
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
...
<StackPanel Visibility="{Binding IsSelected}"
Grid.Row="1">
<TextBox x:Name="textBox"
Text="{Binding Title, Mode=TwoWay}">
<i:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding IsSelected}"
ComparisonCondition="Equal"
Value="Visible">
<local:SetupFocusAction TargetObject="{Binding ElementName=textBox}"/>
</core:DataTriggerBehavior>
</i:Interaction.Behaviors>
</TextBox>
</StackPanel>

WPF - How to view a property name in comboboxitem list

I have a combobox that is binded to collection called Models but it shows the ToString value instead of Name property
<xctk:WatermarkComboBox x:Name="cb_Model" ItemsSource="{Binding Models}" DisplayMemberPath="Name" SelectedValue="{Binding SelectedModel}" Grid.Column="2" Grid.Row="2" Watermark="Vehicle Model"/>
private ObservableCollection<tbl_Model> _models;
public ObservableCollection<tbl_Model> Models
{
get { return _models; }
private set {
_models = value;
NotifyPropertyChanged("Models");
}
}
tbl_Models properties :
Model_No
Name
Manufacturer
The comboboxitem isnt displaying the name property.How can i achieve it without overriding the ToString() method ? Thanks in advance
Seems that it is a bug in WatermarkComboBox. Just specify DataTemplate explicitly, instead of setting DisplayMemberPath:
<xtck:WatermarkComboBox x:Name="cb_Model" ItemsSource="{Binding Models}" SelectedValue="{Binding SelectedModel}" Watermark="Vehicle Model">
<xtck:WatermarkComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</xtck:WatermarkComboBox.ItemTemplate>
</xtck:WatermarkComboBox>

ListBox.SelectedItem and ListBoxItem.IsSelected get out of sync

I have a listbox defined in a WPF window as follows:
<ListBox ItemsSource="{Binding Values}" SelectedItem="{Binding SelectedValue}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Black" Margin="5">
<StackPanel Margin="5">
<TextBlock FontWeight="Bold" Text="{Binding}"/>
<StackPanel Orientation="Horizontal">
<Label>Is Selected: </Label>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Selected Item:</Label>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=SelectedItem}"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And on the view model:
private string selectedValue;
private ObservableCollection<string> values;
public MainWindowViewModel()
{
this.values = new ObservableCollection<string>(new[] { "Fish", "Chips", "Peas" });
}
public ObservableCollection<string> Values
{
get
{
return this.values;
}
}
public string SelectedValue
{
get { return this.selectedValue; }
set
{
this.selectedValue = value;
if (value == "Peas")
{
this.SelectedValue = null;
}
this.OnPropertyChanged();
}
}
Each entry in the listbox displays its text and also a pair of textblocks indicating whether the listboxitem's IsSelected is set, and also what the current SelectedItem of the listbox is.
Everything works fine, until the "Peas" option is selected.
The view model has a piece of code which sets the viewmodel's SelectedValue to null in that instance, which in turn sets the listbox's SelectedItem property to null (overriding the fact that the user just clicked "Peas").
However, the ListBoxItem's IsSelected property for "Peas" does not get set to false even though the ListBox now has no selected item.
Any suggestions how to force the ListBoxItem to have IsSelected=false as well?
OK, I have found a workaround which seems to do the job. I have replaced the block
if (value == "Peas")
{
this.SelectedValue = null;
}
with
if (value == "Peas")
{
Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => this.SelectedValue = null));
}
essentially deferring the setting of the SelectedValue to null until after the block of code handling the user click has completed, and thus ensuring they don't interfere with each other.
I'll mark this as the accepted answer if nobody else has a more "elegant" solution to this!

Categories

Resources