Please help!
I did many research on the internet, but didn't find any solution for my question.
I have a form with foods. There is a grid on the form and with it I can navigate on the food table. There is a combobox on the screen (not in the grid) which contains the categories. The combobox is filled up with the categories from categories table. When I change the record on the datagrid every field updated on the form except the combobox.
first record
second record
So my question is: what I have to do to refresh the combobox, to show the saved category when I navigate on the grid?
In the category table the category has "id" field and in the food table there is a "categoryid" field.
I have this in the xaml file:
<ComboBox x:Name="categoryComboBox" Grid.Row="5" Grid.Column="1" Margin="3,4,20,0" Grid.ColumnSpan="3"
ItemsSource="{Binding Source={StaticResource categoryViewSource}}"
SelectedValuePath="CategoryId"
DisplayMemberPath="CatName"
SelectedItem="{Binding CategoryId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Height="25" VerticalAlignment="Top">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
As I can see you have a small error in your code. I should use the SelectedValue instead of SelectedItem. So change it and I think it will work properly. And in addition You don't need any workaround with the scaling as I suggested before.
Here is example:
XAML
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" >
<ComboBox x:Name="categoryComboBox" ItemsSource="{Binding Source={StaticResource categoryViewSource}}"
SelectedValuePath="CategoryId"
DisplayMemberPath="CatName"
SelectedValue="{Binding CategoryId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Height="25" VerticalAlignment="Top">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
<Button Content="Change Category" Command="{Binding SelectionChangedCommand}"></Button>
</StackPanel>
DataContext
public class MyComboDataContext:BaseObservableObject
{
private int _categoryId;
private ICommand _selectionChangedCommand;
public MyComboDataContext()
{
CategoryId = 1;
}
public int CategoryId
{
get { return _categoryId; }
set
{
_categoryId = value;
OnPropertyChanged();
}
}
public ICommand SelectionChangedCommand
{
get { return _selectionChangedCommand ?? (_selectionChangedCommand = new RelayCommand(SelectionChanger)); }
}
private void SelectionChanger()
{
CategoryId += 1;
if (CategoryId == 4)
CategoryId = 1;
}
}
Explanations:
First of all, this is an example that is simulating the update of a combo. Here the combobox selected value is changed on each button click. In your example the category selection should effect the combo selected value. So each time the grid category selection happens you should push selected category id into the property the combo SelectedValue is bound to it.
In order to help you please update your question with next things:
Are there any Binding expression errors in your output window?
How do you handle a DataGrid selection in your code.
How the data grid selection effects the combobox SelectedValue(it have to be selected value)?
Let me know if you need more help. And feel free to mark you question as answered if my answer was helpful.
Related
Im building a WPF application and trying to stick to the MVVM pattern as much as possible. I have a list box with a data template inside of it that contains a TextBlock and Button. If the button within the data template is clicked it does not select the entire row, so I am unaware of what row it pertains to. I would like to grab the entire object and bind it to a property in the view model. Can I get some help or a workaround for this please that sticks to mvvm pattern.
List box with item template
<telerik:RadListBox Width="200" Height="150" HorizontalAlignment="Left" Margin="10" ItemsSource="{Binding ListOfSupplierInvoices}"
SelectedItem="{Binding SelectedSupplierInvoice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<telerik:RadListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" >
<TextBlock Text="{Binding InvoiceNumber}" HorizontalAlignment="Left" Margin="5" ></TextBlock>
<telerik:RadButton Height="20" >
<telerik:RadButton.Content>
<Image Source="/ImageResources/Misc/delete.png" Stretch="Fill" />
</telerik:RadButton.Content>
</telerik:RadButton>
</StackPanel>
</DataTemplate>
</telerik:RadListBox.ItemTemplate>
</telerik:RadListBox>
How it looks in the view:
As far as I understand your code, the button corresponds to a delete command, which means you want to delete the item associated with the button. In this case, the selection might not need to change, you just have to pass the current item to the delete command.
Add a Delete command to your view model like this:
public class MyViewModel : ViewModelBase
{
public MyViewModel()
{
Delete = new DelegateCommand(ExecuteDelete, CanExecuteDelete);
// ...other code.
}
public ICommand Delete { get; }
private void ExecuteDelete(object obj)
{
var invoiceItem = (InvoiceItem) obj;
// Use this only if you need the item to be selected.
// SelectedSupplierInvoice = invoiceItem;
// ...your delete logic.
}
private bool CanExecuteDelete(object obj)
{
// ...your can execute delete logic.
}
// ...other code.
}
Note that I introduced InvoiceItem as item type, because I do not know your item type, simply adapt it. The Delete command gets the current item passed as parameter. If you can always remove the item, there is no need in selecting it, as it is gone afterwards.
Otherwise, uncomment the line so the SelectedSupplierInvoice is set to the item which will automatically update the user interface through the two-way binding if you have implemented INotifyPropertyChanged correctly or derive from ViewModelBase which exposes the RaisePropertyChanged or OnPropertyChanged method, e.g.:
private InvoiceItem _selectedSupplierInvoice;
public InvoiceItem SelectedSupplierInvoice
{
get => _selectedSupplierInvoice;
set
{
if (_selectedSupplierInvoice == value)
return;
_selectedSupplierInvoice = value;
RaisePropertyChanged();
}
}
In your XAML wire the button to the Delete command on the DataContext of the RadListBox.
<telerik:RadButton Height="20"
Command="{Binding DataContext.Delete, RelativeSource={RelativeSource AncestorType={x:Type telerik:RadListBox}}}"
CommandParameter="{Binding}">
<telerik:RadButton.Content>
<Image Source="/ImageResources/Misc/delete.png" Stretch="Fill" />
</telerik:RadButton.Content>
</telerik:RadButton>
I have a combobox which allows users to select from a collection of images. Because of the size of the images I would like to not display the image in the combobox once an image has been selected. I simply want nothing displayed in the combobox when an item is selected.
So far I have tried setting the selectedImageIndex to -1 once the selectedImageSource has been set when the user makes a selection however this did not work as the first image at [0] is still displayed in the combobox by default. I am using MVVM.
XAML
<ComboBox Grid.Row="1" SelectedIndex="{Binding SelectedImageIndex}" ItemsSource="{Binding SymbolImageCollection}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Img}" Width="50" Height="50"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="300" HorizontalAlignment="Left"/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
View Model
public ObservableCollection<SymbolImage> SymbolImageCollection { get { return AppearanceLayerProperties.Instance.SymbolImageCollection; } }
private string _selectedImageSource;
public string SelectedImageSource
{
get { return _selectedImageSource; }
set
{
SetProperty(ref _selectedImageSource, value);
//SelectedImageIndex = -1;
}
}
private int _selectedImageIndex;
public int SelectedImageIndex
{
get { return _selectedImageIndex; }
set
{
var selectedImage = AppearanceLayerProperties.Instance.SymbolImageCollection[value].ImgSource;
SelectedImageSource = selectedImage;
SetProperty(ref _selectedImageIndex, -1);
}
}
Changing the selection back to null after selecting an item of the ComboBox is not good practice, because if you need to use the selected value, it is not available anymore.
A solution could be to have a different template for the selected item of the ComboBox. That way, you could remove the image, but in its place put something else, like text, so the user as an idea of what item is selected. Here is a previous StackOverflow post explaining how to do this :
Can I use a different Template for the selected item in a WPF ComboBox than for the items in the dropdown part?
I hope this helps!
Hello I have been searching everywhere for a solution to this problem and cannot figure out a solution.
I have a combo box in a datagrid column that I want to bind it's itemsource to a list generated by a database.
I also want to bind the selected value to a separate table.
I have succeeded in doing this... but only sometimes. There is something not synchronized.
Here is some code
xaml:
<Grid.Resources>
<my:CategoriesProvider x:Key="categoriesProvider"/>
</Grid.Resources>
..........................................
<data:DataGridTemplateColumn Header="Category" Width="100" x:Name="cboDataCol">
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate x:Name="cboDataTemplate">
<ComboBox Name="cboCategories" SelectedItem="{Binding category, Mode=TwoWay}" ItemsSource="{Binding CategoriesList,Source={StaticResource categoriesProvider}}" DisplayMemberPath="name" SelectedValue="{Binding Path=category.id}" SelectedValuePath="id"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
C#:
public class CategoriesProvider : List<category>
{
MenuItems.MenuItemService.MenuItemServiceClient svc = new MenuItems.MenuItemService.MenuItemServiceClient();
ObservableCollection<category> allCategories;
public CategoriesProvider()
{
svc.getCategoriesCompleted += new EventHandler<getCategoriesCompletedEventArgs>(svc_getCategoriesCompleted);
svc.getCategoriesAsync();
}
public void svc_getCategoriesCompleted(object sender, getCategoriesCompletedEventArgs e)
{
//m_autoresetevent.Set();
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
allCategories = e.Result;
if (allCategories == null)
{
MessageBox.Show("NULL123");
}
});
}
Sometimes it seems that the control gets bound to the list before getItemsAsync is completed. Is there a solution to doing it this way, or should I give up and try something else?
Thanks
Try implementing INotifyPropertyChanged on your CategoriesProvider. Where is CategoriesList? That's what you should be notifying changed.
I'm a bit puzzled:
this works:
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Rol" />
<ComboBox ItemTemplate="{StaticResource listRollen}"
Height="23" Width="150"
SelectedItem="{Binding Path=SelectedRol, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ItemsSource="{Binding Path=allRollen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
and the property for SelectedRol is:
public TblRollen SelectedRol
{
get { return _selectedRol; }
set
{
if (_selectedRol != value)
{
_selectedRol = value;
OnPropertyChanged("SelectedRol");
}
}
}
But this doesn't work:
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Soort" />
<ComboBox ItemTemplate="{StaticResource listSoorten}"
Height="23" Width="150"
ItemsSource="{Binding Path=allSoorten}"
SelectedItem="{Binding Path=SelectedProduct, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
with following property SelectedProduct:
public TblProduktSoorten SelectedProduct
{
get { return _selectedPSoort; }
set
{
if (_selectedPSoort != value)
{
_selectedPSoort = value;
OnPropertyChanged("SelectedProduct");
}
}
}
somewhere in my code I set SelectedProduct = p.TblProduktSoorten and while debugging, I see the property gets set correctly...
Combobox inside a DataGrid?
If the combobox is in a DataGrid you must add this :
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged
See this : https://stackoverflow.com/a/5669426/16940
Try to use not selected item but value path look at the code sample
<ComboBox Name="projectcomboBox" ItemsSource="{Binding Path=Projects}" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="FullName"
SelectedValuePath="Name" SelectedIndex="0" Grid.Row="1" Visibility="Visible" Canvas.Left="10" Canvas.Top="24" Margin="11,6,13,10">
</ComboBox>
the binding property is
public ObservableCollection<Project> Projects
{
get { return projects; }
set
{
projects = value;
RaisePropertyChanged("Projects");
}
}
This might be related to the fact that apparently attribute order does matter, in your second case the ItemsSource and SelectedItem declarations are swapped.
If you set the SelectedProduct property when SelectedProduct is changed in the property changed event handler, you need to set this property asynchronously.
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedProduct")
App.Current.Dispatcher.InvokeAsync(() => SelectedProduct = somevalue);
}
My problem was caused by my own tired brain. Same symptom, maybe it will kick you into seeing your problem.
Setting the SelectedItem must be given an item in the List!! (duhh) Normally this happens naturally but I had a case I got a "Role" from another service (Same object type) and was trying to set it and expecting the combobox to change! ;(
instead of -
Roles = roles;
CurrentRole = role;
remember to do this -
Roles = roles;
CurrentRole = roles.FirstOrDefault(e=> e.ID == role.ID); //(System.Linq)
I don't know if you fixed it yet, but I encountered the same issue today.
It was fixed by making sure the collection for selecteditems was an ObservableCollection.
I think this problem is caused by the type of ItemSource and SelectedItem is mitchmatched.
For example, if the ItemSource is binded to a List of int and the SelectedItem is binded to a string. If you set selected item to null or empty string, the combobox cannot know what item is selected. So the combobox will show nothing.
This might be old but I have not seen the trick that did it for me; I had to add NotifyOnSourceupdate=true to my SelectedItem in the ComboBox
This had me stumped for a while inside a DataGrid, using SelectedItem. Everything was fine but I am deserializing the app state which loads the items and also has a selected item. The collection was there but the selected isn't actually visible until I used the Text="{Binding Path=Score.SelectedResult.Offset}"
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ToolTip="Score offset results"
ItemsSource="{Binding Score.SearchResults,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Score.SelectedResult, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding Path=Score.SelectedResult.Offset}"
SelectedValuePath="Offset"
DisplayMemberPath="Offset"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
So I have several comboboxes in my WPF application that don't change the selection when a user clicks on the text of a combobox item. In order to select a particular item you have to click to the right or left of the text. I have another combobox that selects just fine when the text is clicked. The only difference between the two is databinding. The comboboxes that don't select when the text is clicked are databound to an ObservableCollection of one type or another. The combobox that works has manually inserted, static values.
I've searched the issue extensively and I can't seem to find anyone else who has had this issue or anything remotely similar. I'm not setting any weird properties.
Here is the code for one of the problematic comboboxes:
<ComboBox HorizontalAlignment="Left" Margin="40,160,0,0" VerticalAlignment="Top" Width="132" ItemsSource="{Binding Path=Systems}" SelectedItem="{Binding Path=System}" SelectedIndex="0">
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding Path=Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Here is a video of the behavior:
http://www.youtube.com/watch?v=D0r1N1ghw-k
enter code hereSuppose my Combobox is defind as below
<ComboBox Name="cmb" Width="200" Height="20" DisplayMemberPath="PersonName" SelectedValuePath="PersonID">
</ComboBox>
please notice , i have removed the itemtemplate part
and my model is as below
public class Person
{
public string PersonName { get; set; }
public string PersonID { get; set; }
}
And my binding is in code behind , this step is not necessary , you can do it in the xaml , iam just checking quickly so much dirty code
public List<Person> source = new List<Person>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 20; i++)
{
source.Add(new Person() { PersonID = i.ToString(), PersonName = "Sau" + i.ToString() });
}
cmb.ItemsSource = source;
this.DataContext = this;
}
so if you run this sample , you will see you can select the value when you click on the text itself.
it's content property which causes some problem but i am not 100% sure on this.