I'm using wpf c# and Entity Framework
I have a DataGrid on that show data from database
when users click on datagrid that row will show items in ComboBox (Load on of columns in combobox)
but problem is combobox doesn't show Normal list
Code CS Behind :
DENAF1399Entities dbms = new DENAF1399Entities();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var qre = dbms.Database.SqlQuery<Q_View>("SELECT * FROM Q_View");
datagrid1.ItemsSource = qre.ToList();
}
private void datagrid1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Q_View QVkala = datagrid1.SelectedItem as Q_View;
if (QVkala != null)
{
combobox1.ItemsSource = QVkala.NAMES;
}
}
I tried
-Change Fonts of combobox
-use new combobox
but didn't work
please help me
Edit during formation: It just became obvious to me what's going on. Q_View.NAMES is a string, and by setting combobox1.ItemsSource to that property, it's identifying the individual items as characters in the string (as string is an IEnumerable<char>).
If what you want in the combo box is what's in each of the columns of the selected item, then the way to do that is like this:
private void datagrid1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Q_View QVkala = datagrid1.SelectedItem as Q_View;
if (QVkala != null)
{
object[] items = { QVkala.CODE, QVkala.NAME, QVkala.NAMES, QVkala.TOZIH } //etc whatever properties you want to project into this
combobox1.ItemsSource = items;
}
}
ORIGINAL WORK ON AN ANSWER
At first glance it looks like your data is transposed, but altogether it looks like you aren't using WPF or Entity Framework like you really could be using them. WPF was made for MVVM design and Entity Framework was made for treating tables like collections of objects. Not knowing much else about your application, here's how I'd get started:
First, I'd move basically everything except what's auto-generated out of MainWindow.xaml.cs, and start a new separate class. (Note: may have compiler errors as this is completely off the cuff)
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; //MainWindow.xaml will hook into this
public ObservableCollection<Q_View> Q_Views { get; private set; }
private Q_View selectedQView;
public Q_View SelectedQView
{
get => selectedQView;
set
{
if(value != selectedQView)
{
selectedQView = value;
PropertyChanged?.Invoke("SelectedQView");
}
}
}
}
And then in MainWindow.xaml.cs, the only change from what's generated would be the constructor (there's another way to do this even without changing the code-behind but I'll not get into it here since I'm not as xaml-adept as I am with C#)
public class MainWindow : Window
{
public MainWindow()
{
DataContext = new MainWindowViewModel();
InitializeComponent(); //that's auto-generated
}
}
And finally, the xaml for your DataGrid. Edit it like this:
<DataGrid Name="QViewDataGrid" AutoGenerateColumns="False" ItemsSource="{Binding Q_Views}" SelectedItem="{Binding SelectedQView}">
<DataGrid.Columns>
<DataGridTextColumn Header="CODE" Binding="{Binding Path="CODE"}"> //and so forth with more columns
</DataGrid.Columns>
</DataGrid>
ComboBox will have a similar syntax for binding an ItemsSource and SelectedItem. Doing this enables you to avoid having event handlers and dealing with boiler plate for updating so many things.
Is there a way to bind directly to a Collection in the model and manually tell WPF that the binding needs refreshing without having to create an ObservableCollection for it in the viewmodel?
<ListBox ItemsSource="{Binding Position.PossibleMoves}">
...
</ListBox>
Position is my model, part of a chess library, and PossibleMoves is a Collection within it. I do not want to implement INotifyProperty changed or put ObservableCollections in a stand alone optimized library.
I want to avoid copying PossibleMoves into an ObservableCollection every time the position is updated. The data binding works on initialization but it would be handy if I could also refresh the binding at will inside the viewmodel.
Calling OnNotifyPropertyChanged("Position.PossibleMoves") from the viewmodel doesn't work because the reference to the collection itself does not change.
You can do this by using an attached behavior to bind a handler to an event that gets triggered in the view model. You can't bind directly to events though so you have to wrap them in a class like so:
public class Refresher
{
public delegate void RefreshDelegate();
public event RefreshDelegate Refresh;
public void DoRefresh()
{
if (this.Refresh != null)
this.Refresh();
}
}
Now add an instance of that to your view model:
public class MyViewModel
{
public IList<string> Items { get; set; }
private Refresher _Refresher = new Refresher();
public Refresher Refresher {get {return this._Refresher;}}
}
Next create an attached behavior that registers a delegate instance with that event and forces the listbox to refresh its binding:
public static class RefreshBehavior
{
public static readonly DependencyProperty RefresherProperty = DependencyProperty.RegisterAttached(
"Refresher",
typeof(Refresher),
typeof(RefreshBehavior),
new PropertyMetadata(null, OnRefresherChange));
public static void SetRefresher(DependencyObject source, Refresher value)
{
source.SetValue(RefresherProperty, value);
}
public static Refresher GetRefresher(DependencyObject source)
{
return (Refresher)source.GetValue(RefresherProperty);
}
private static void OnRefresherChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Refresher.RefreshDelegate handler = () =>
{
var listBox = d as ListBox;
listBox.Items.Refresh();
};
if (e.NewValue != null)
(e.NewValue as Refresher).Refresh += handler;
if (e.OldValue != null)
(e.OldValue as Refresher).Refresh -= handler;
}
}
And finally attach it to your listbox in the xaml:
<ListBox ItemsSource="{Binding Items}"
local:RefreshBehavior.Refresher="{Binding Refresher}"/>
That's it. Call Refresher.DoRefresh() in your view model and it will force a listbox update.
This works but it's really hammering a square peg into a round hole. If I were you I'd do everything I could to try and do proper collection changed notification in your view model. I understand you wanting to keep ObservableCollection out of your model but there are ways to proxy change notification automatically (e.g. Castle DynamicProxy).
You need to NotifyPropertyChange for the PossibleMoves from inside the Position class or make a property that delegates to the Position.PossibleMoves and notify that one.
I am trying to create a Custom control derived from a standard Grid.
I added a ObservableCollection as a DependencyProperty of the Custom control. However, the get/set of it is never reached. Can I have some guidelines in creating a DependencyProperty that works correctly with and ObservableCollection?
public class MyGrid : Grid
{
public ObservableCollection<string> Items
{
get
{
return (ObservableCollection<string>)GetValue(ItemsProperty);
}
set
{
SetValue(ItemsProperty, value);
}
}
public static DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(ObservableCollection<string>),
typeof(MyGrid), new UIPropertyMetadata(null, OnItemsChanged));
}
I would suggest not to use ObservableCollection as the type of an Items dependency property.
The reason for having an ObservableCollection here (I guess) is to enable the UserControl to attach a CollectionChanged handler when the property value is assigned. But ObservableCollection is too specific.
The approach in WPF (e.g. in ItemsControl.ItemsSource) is to define a very basic interface type (like IEnumerable) and when the property is assigned a value, find out if the value collection implements certain more specific interfaces. This would at least be INotifyCollectionChanged here, but the collection might also implement ICollectionView and INotifyPropertyChanged. All these interfaces wouldn't be mandatory and that would enable your dependency property to bind to all sorts of collections, starting with a plain array up to a complex ItemCollection.
Your OnItemsChanged property change callback would then look like this:
private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyGrid grid = obj as MyGrid;
if (grid != null)
{
var oldCollectionChanged = e.OldValue as INotifyCollectionChanged;
var newCollectionChanged = e.NewValue as INotifyCollectionChanged;
if (oldCollectionChanged != null)
{
oldCollectionChanged.CollectionChanged -= grid.OnItemsCollectionChanged;
}
if (newCollectionChanged != null)
{
newCollectionChanged.CollectionChanged += grid.OnItemsCollectionChanged;
// in addition to adding a CollectionChanged handler
// any already existing collection elements should be processed here
}
}
}
private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// handle collection changes here
}
The WPF binding mechanism may bypass your standard CLR property and go directly to the dependency property accessors (GetValue and SetValue).
That is why logic should not be placed inside of the CLR property, but instead inside a changed handler.
Also the ObservableCollection<string> will never be set because when you use collection properties from XAML, like the following:
<local:MyGrid>
<local:MyGrid.Items>
<sys:String>First Item</sys:String>
<sys:String>Second Item</sys:String>
</local:MyGrid.Items>
</local:MyGrid>
It is actually calling a get on Items and then calling Add for each of the elements.
I am searching about how to create the columns of the DataGrid from the ToolKit dynamic in MvvM way. But looks like it is impossible !
Is there some one that had to do the samething ?
there is no need to create a usercontrol or another control that comes from DataGrid, I just want to set de ItemSource of the grid to my custom object and in some point I want to define the columns of the grid in runtime dynamic based in the kind of the object.
Is that possible ?
cheers
I'm going to preface this by saying it maybe isn't the best solution to be doing and may not work in some situations but you can give it a try and see if it will work for what you want. I just whipped this up so it may have some bugs in it. Its still going to involve some code, but it keeps your model from knowing about you view.
What you need to do is create an extension property that will allow you to bind the Columns property on the DataGrid. Here is an example that I put together.
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
public static class DataGridExtension
{
public static ObservableCollection<DataGridColumn> GetColumns(DependencyObject obj)
{
return (ObservableCollection<DataGridColumn>)obj.GetValue(ColumnsProperty);
}
public static void SetColumns(DependencyObject obj, ObservableCollection<DataGridColumn> value)
{
obj.SetValue(ColumnsProperty, value);
}
public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.RegisterAttached("Columns",
typeof(ObservableCollection<DataGridColumn>),
typeof(DataGridExtension),
new UIPropertyMetadata (new ObservableCollection<DataGridColumn>(),
OnDataGridColumnsPropertyChanged));
private static void OnDataGridColumnsPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
if (d.GetType() == typeof(DataGrid))
{
DataGrid myGrid = d as DataGrid;
ObservableCollection<DataGridColumn> Columns =
(ObservableCollection<DataGridColumn>)e.NewValue;
if(Columns != null)
{
myGrid.Columns.Clear();
if (Columns != null && Columns.Count > 0)
{
foreach (DataGridColumn dataGridColumn in Columns)
{
myGrid.Columns.Add(dataGridColumn);
}
}
Columns.CollectionChanged += delegate(object sender,
NotifyCollectionChangedEventArgs args)
{
if(args.NewItems != null)
{
foreach (DataGridColumn column
in args.NewItems.Cast<DataGridColumn>())
{
myGrid.Columns.Add(column);
}
}
if(args.OldItems != null)
{
foreach (DataGridColumn column
in args.OldItems.Cast<DataGridColumn>())
{
myGrid.Columns.Remove(column);
}
}
};
}
}
}
}
Then you attach it to you DataGrid like this (Where columns is the an ObservableCollection property on your view model)
<Controls:DataGrid AutoGenerateColumns="False"
DataGridExtension.Columns="{Binding Columns}" />
I'm not sure how well it is going to respond if you start adding and remove columns, but it seems to work from my basic testing. Good Luck!
Having a similar problem, I did not want to add another dependency property.
My workaround was to organise the data to display in the DataGrid in a DataTable and bind the DataGrid ItemSource property to this DataTable (with of course AutoGenerateColumns set to true).
It works well, DataGrids seem happy with DataTable as source.
I would like to extend the previous example (answer) the ability to subscribe and unsubscribe on event CollectionChanged. Link on my answer in related theme.
I've got a simple problem in my WPF application which has me banging my head on the table. I have a TabControl, where every TabItem is a View generated for a ViewModel using a DataTemplate similar to this:
<DataTemplate DataType="{x:Type vm:FooViewModel}">
<vw:FooView/>
</DataTemplate>
FooView contains a ComboBox:
<ComboBox ItemsSource="{Binding Path=BarList}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedBar}"/>
and FooViewModel contains a simple Property: public Bar SelectedBar { get; set; }. My problem is that when I set the value for my ComboBox, change to another tab, then change back, the ComboBox is empty again. If I set a breakpoint on the setter for my property, I see that the property is assigned to null when I switch to another tab.
From what I understand, when a tab is switched, it is removed from the VisualTree - but why is it setting my ViewModel's property to null? This is making it very difficult for me to hold persistent state, and checking value != null does not seem like the right solution. Can anyone shed some like on this situation?
Edit: The call stack at the setter breakpoint only shows [External Code] - no hints there.
We just ran into the same problem. We found a blog entry describing the problem. It looks like it is a BUG in WPF and there is a workaround:
Specify the SelectedItem binding before the ItemsSource binding and the problem should be gone.
blog article
TLDR;
Change:
<ComboBox ItemsSource="{Binding Countries, Mode=OneWay}"
SelectedItem="{Binding SelectedCountry}"
DisplayMemberPath="Name" >
</ComboBox>
To:
<ComboBox SelectedItem="{Binding SelectedCountry}"
ItemsSource="{Binding Countries, Mode=OneWay}"
DisplayMemberPath="Name" >
</ComboBox>
My app is using avalondock & prims and had that exact problem. I has same thought with BSG, when we switched tab or document content in MVVM app, the controls as listview+box, combobox is removed from VisualTree. I bugged and saw most data of them was reset to null such as itemssource, selecteditem, .. but selectedboxitem was still hold current value.
A approach is in model, check its value is null then return like this:
private Employee _selectedEmployee;
public Employee SelectedEmployee
{
get { return _selectedEmployee; }
set
{
if (_selectedEmployee == value ||
IsAdding ||
(value == null && Employees.Count > 0))
{
return;
}
_selectedEmployee = value;
OnPropertyChanged(() => SelectedEmployee);
}
But this approach can only solve quite good in first binding level. i mean,
how we go if want to bind SelectedEmployee.Office to combobox, do same is not good
if check in propertyChanged event of SelectedEmployee model.
Basically, we dont want its value is reset null, keep its pre-value. I found a new solution
consistently. By using attached property, i created KeepSelection a-Pro, bool type, for Selector controls, thus supply all its inherited suck as listview, combobox...
public class SelectorBehavior
{
public static bool GetKeepSelection(DependencyObject obj)
{
return (bool)obj.GetValue(KeepSelectionProperty);
}
public static void SetKeepSelection(DependencyObject obj, bool value)
{
obj.SetValue(KeepSelectionProperty, value);
}
// Using a DependencyProperty as the backing store for KeepSelection. This enables animation, styling, binding, etc...
public static readonly DependencyProperty KeepSelectionProperty =
DependencyProperty.RegisterAttached("KeepSelection", typeof(bool), typeof(SelectorBehavior),
new UIPropertyMetadata(false, new PropertyChangedCallback(onKeepSelectionChanged)));
static void onKeepSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = d as Selector;
var value = (bool)e.NewValue;
if (value)
{
selector.SelectionChanged += selector_SelectionChanged;
}
else
{
selector.SelectionChanged -= selector_SelectionChanged;
}
}
static void selector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selector = sender as Selector;
if (e.RemovedItems.Count > 0)
{
var deselectedItem = e.RemovedItems[0];
if (selector.SelectedItem == null)
{
selector.SelectedItem = deselectedItem;
e.Handled = true;
}
}
}
}
Final, i use this approach simply in xaml:
<ComboBox lsControl:SelectorBehavior.KeepSelection="true"
ItemsSource="{Binding Offices}"
SelectedItem="{Binding SelectedEmployee.Office}"
SelectedValuePath="Id"
DisplayMemberPath="Name"></ComboBox>
But, selecteditem will never null if selector's itemssource has items. It may affect
some special context.
Hope that helps.
Happy conding! :D
longsam
I had this same problem when scrolling through a virtualizing DataGrid that contains ComboBoxes. Using IsSynchronizedWithCurrentItem did not work, nor did changing the order of the SelectedItem and ItemsSource bindings. But here is an ugly hack that seems to work:
First, give your ComboBox an x:Name. This should be in the XAML for a control with a single ComboBox. For example:
<ComboBox x:Name="mComboBox" SelectedItem="{Binding SelectedTarget.WritableData, Mode=TwoWay}">
Then add these two event handlers in your codebehind:
using System.Windows.Controls;
using System.Windows;
namespace SATS.FileParsing.UserLogic
{
public partial class VariableTargetSelector : UserControl
{
public VariableTargetSelector()
{
InitializeComponent();
mComboBox.DataContextChanged += mComboBox_DataContextChanged;
mComboBox.SelectionChanged += mComboBox_SelectionChanged;
}
/// <summary>
/// Without this, if you grab the scrollbar and frantically scroll around, some ComboBoxes get their SelectedItem set to null.
/// Don't ask me why.
/// </summary>
void mComboBox_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
mComboBox.GetBindingExpression(ComboBox.SelectedItemProperty).UpdateTarget();
}
/// <summary>
/// Without this, picking a new item in the dropdown does not update IVariablePair.SelectedTarget.WritableData.
/// Don't ask me why.
/// </summary>
void mComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
mComboBox.GetBindingExpression(ComboBox.SelectedItemProperty).UpdateSource();
}
}
}
Generally, I use SelectedValue instead of SelectedItem. If I need the object associated with the SelectedValue then I add a lookup field containing this to the target object (as I use T4 templates to gen my viewmodels this tends to be in a partial class). If you use a nullable property to store the SelectedValue then you will experience the problem described above, however if binding the SelectedValue to a non-nullable value (such as an int) then the WPF binding engine will discard the null value as being inappropriate for the target.
Edit:
Below stuff works (I hope...); I developed it because I followed the SelectedItems route described on the MVVM Lite page. However - why do I want to rely on SelectedItems? Adding an IsSelected property to my Items (as shown here) automatically preserves selected items (short of the mentioned cavet in above link). In the end, much easier!
Inital Post:
ok - that was a piece of work; I've a multi-column ListView with SelectionMode="Extension", which makes the whole thing fairly complex. My starting point is invoking tabItems from workspaces similar as describe here.
I made sure that in my ViewModel, I know when a tab item (workspace) is active. (This is a bit similar to here) - of course, somebody needs initalize SelectedWorkspace first.
private Int32 _selectedWorkspace;
public Int32 SelectedWorkspace {
get { return _selectedWorkspace; }
set {
_selectedWorkspace = value;
base.OnPropertyChanged("SelectedWorkspace");
}
}
protected Int32 _thisWorkspaceIdx = -1;
protected Int32 _oldSelectedWorkspace = -1;
public void OnSelectedWorkspaceChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "SelectedWorkspace") {
if (_oldSelectedWorkspace >= 0) {
Workspaces[_oldSelectedWorkpace].OnIsActivatedChanged(false);
}
Workspaces[SelectedWorkspace].OnIsActivatedChanged(true);
_oldSelectedWorkspace = SelectedWorkspace;
}
}
protected bool _isActive = false;
protected virtual void OnIsActivatedChanged(bool isActive) {
_isActive = isActive;
}
This allowed me to update the ViewModel selected items only if the tab item (workspace) was actually active. Hence, my ViewModel selected items list is preserved even as the tab item clears the ListView.SelectedItems. In the ViewModel:
if (_isActive) {
// ... update ViewModel selected items, referred below as vm.selectedItems
}
Last, when the tabItem got re-enabled, I hooked up to the 'Loaded' event and restored the SelectedItems. This is done in the code-behind of the View. (Note that whilst my ListView has multiple columns, one serves as a key, the others are for information only. the ViewModel selectedItems list only keeps the key. Else, the comparison below would be more complex):
private void myList_Loaded(object sender, RoutedEventArgs e) {
myViewModel vm = DataContext as myViewModel;
if (vm.selectedItems.Count > 0) {
foreach (string myKey in vm.selectedItems) {
foreach (var item in myList.Items) {
MyViewModel.MyItem i = item as MyViewModel.MyItem;
if (i.Key == myKey) {
myList.SelectedItems.Add(item);
}
}
}
}
}
if you suing async selection in WPF then remove it IsSynchronizedWithCurrentItem="True" from for the ComboBox, please refer to the document about IsSynchronizedWithCurrentItem:
<ComboBox
Name="tmpName"
Grid.Row="10"
Width="250"
Text="Best Match Position List"
HorizontalAlignment="Left"
Margin="14,0,0,0"
SelectedItem="{Binding Path=selectedSurceList,Mode=TwoWay}"
ItemsSource="{Binding Path=abcList}"
DisplayMemberPath="Name"
SelectedValuePath="Code"
IsEnabled="{Binding ElementName=UserBestMatchYesRadioBtn,Path=IsChecked}">
</ComboBox>
also takecare the binding
first use SelectedItem
then ItemsSource
ref:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/fb8a8ad2-83c1-43df-b3c9-61353979d3d7/comboboxselectedvalue-is-lost-when-itemssource-is-updated?forum=wpf
http://social.msdn.microsoft.com/Forums/en-US/c9e62ad7-926e-4612-8b0c-cc75fbd160fd/bug-in-wpf-combobox-data-binding
I solve my problem using the above
I once had a similar problem. It seems that the combobox looses the selected item in VisibilityChanged event. Workarround is to clear the binding before this occurs, and reset it when coming back. You can also try to set the Binding to Mode=TwoWay
Hope that this helps
Jan
I had the same problem and solved it with the following method attached to the Combobox DataContextChanged-Event:
private void myCombobox_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (sender is FrameworkElement && e.NewValue == null)
((FrameworkElement)sender).DataContext = e.OldValue;
}
So everytime you want to remove the datacontext from the combobox, the old datacontext will be set again.
Everytime you change the active Tab of your TabControl, the Combobox will removed from your VisualTree and added if you go back to the one with your combobox. If the combo box is removed from the VisualTree, also the DataContext is set to null.
Or you use a class, which have implemented such feature:
public class MyCombobox : ComboBox
{
public MyCombobox()
{
this.DataContextChanged += MyCombobox_DataContextChanged;
}
void MyCombobox_DataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
if (sender is FrameworkElement && e.NewValue == null)
((FrameworkElement)sender).DataContext = e.OldValue;
}
public void SetDataContextExplicit(object dataContext)
{
lock(this.DataContext)
{
this.DataContextChanged -= MyCombobox_DataContextChanged;
this.DataContext = dataContext;
this.DataContextChanged += MyCombobox_DataContextChanged;
}
}
}
I think the problem may be that you arent telling the Combo box when to bind back to the source. Try this:
<ComboBox ItemsSource="{Binding Path=BarList}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedBar, UpdateSourceTrigger=PropertyChanged}"/
You can use the MVVM framework Catel and the catel:TabControl element there this problem is already solved.
Just don't allow your ViewModel's property to be changed if value becomes null.
public Bar SelectedBar
{
get { return barSelected; }
set { if (value != null) SetProperty(ref barSelected, value); }
}
That's it.