KeyDown problem with Silverlight & MVVM - silverlight

First of all, I am new to the Silverlight + MVVM world. So I will try my best to explain the scenario to you guys.
I have the following AutoCompleteBox in my Silverlight 4 application which works perfect.
<myControls:AutoCompleteBox Name="acbVendorID" MinimumPrefixLength="2"
ItemsSource="{Binding VendorCodes, Mode=TwoWay}"
SelectedItem="{Binding SelectedVendorCode, Mode=TwoWay}"
ValueMemberBinding="{Binding Value}"
cmds:AutoCompletePopulating.Command="{Binding VendorID_Populating}"
cmds:AutoCompletePopulating.CommandParameter="{Binding ElementName=acbVendorID}">
Now my requirement is as follows:
When I select a particular VendorId from the AutoCompleteBox, the rest of the Vendor data should load in a gridview. For this reason, I have implemented the SelectedVendorCode in my ViewModel in the following way:
private KeyValue selectedVendorCode;
public KeyValue SelectedVendorCode
{
get { return selectedVendorCode; }
set
{
if (selectedVendorCode != value)
{
selectedVendorCode = value;
this.NotifyChanged("SelectedVendorCode");
if (selectedVendorCode != null)
{
this.VendorDisplayCode = selectedVendorCode.Value;
OnVendorCodeSelected(); //Sets the vendor collection property bound to the GridView
}
}
}
}
This works fine as well. The problem comes when the user uses the down arrow to browse through the items in AutoCompleteBox, The data in the Grid View gets reloaded as the selected item of the AutoCompleteBox changes.
I want to block this particular functionality. I want the GridView data to be fetched only when the user selects a vendor in the AutoCompleteBox and then presses Enter
I tried to achieve this using the method mentioned in this link
The KeyPressCommand doesn't fire when I use Down Arrow Or The Enter Key. Most other keys seem to fire this command.
I am a little perplexed by this. Any inputs by you giuys would be really helpful.
Thanks in advance.
~Vinod

Jeff Wilcox has written a post to do just this. The key is to implement a new ISelectionAdapter and apply to your ListBox. I have done this in the past and it works great.

Related

WPF DataGrid automatically updates in-memory data?

I'm using WPF and MVVM pattern to develop a desktop application. Maybe I'm not clear about how a DataGrid control would work, but if I modify an item (text, checkbox, etc.), the modification persists even if I don't make any permanent database update (using Entity Framework). For example, I may switch to view different data, and when I come back to view the grid with modified data (but without saving to db), the change is there. Somehow the in-memory data has been changed by the DataGrid control and is not refreshed or synced with database.
In other words, the data in the DataGrid remained modified until I stop and re-run it from visual studio.
UPDATED:
Another way to ask this question would be: What actually happens when I update, say, an item of a DataGrid? If it is bound to a ViewModel's property P in two-way mode then I suppose P will be updated. But even if I refresh its value (setting the P to null then calling the data access methods again), the modified data are still there.
Does anybody have any idea of what happened?
Thanks!
UPDATED 2:
Here is the xaml code which binds a DataGrid to a property named UserList in the ViewModel.
<DataGrid
x:Name="UserList"
ItemsSource="{Binding UserList, Mode=TwoWay}"
AutoGenerateColumns="False"
AllowDrop="True"
RowBackground="Orange"
AlternatingRowBackground="#FFC4B0B0">
<!-- define columns to view -->
<DataGrid.Columns>
...
</DataGrid.Columns>
</DataGrid>
Here is the code running in the ViewModel. The method InitialiseData() is called in the constructor of the VM and before I want to do something else with persistent data, so I supposed is always refreshed.
private void InitialiseData()
{
// Retrieves user list from the business layer's response
Response userList = _userBL.GetUserList();
if (userList is FailResponse)
{
MessageBox.Show(userList.Message);
return;
}
else
{
UserList = null;
UserList = (IEnumerable<User>)((SuccessResponse)userList).Data;
}
** UPDATED 3 **:
private IEnumerable<User> _userList;
public IEnumerable<User> UserList
{
get
{
return _userList;
}
set
{
_userList = value;
NotifyOfPropertyChange(() => UserList);
}
}
If you switch back, you are switching to in-memory collection which was updated by DataGrid before. Or do you load data from dtb again?
EDIT:
Ok, now as you have posted the code, I know where is the problem.
DataGrid is not refreshed as I thought. Make sure, you will raise NotifyProperyChanged on the property UserList. Then it will work. See ObservableCollection class as well.

Looping through (and removing) items of a bound ComboBox

I am new to WPF - and painfully aware of it. I have unsuccessfully searched for answers to this particular problem and am now seeking advice from my more knowledgeable peers!
The scenario
The application on which I am working allows users to either enter new records into a database, or amend existing ones.
I have a form containing a bound ComboBox. It is populated from the database, which is accessed by a WPF service that exposes a DTO.
From the UI perspective, the form has two modes:
1. enter new record
2. amend existing record
The ComboBox in question appears in both cases, but the requirement is to have fewer options visible when the form is in 'amend' mode.
What I am trying to do is loop through the ComboBox items when the form is in 'amend' mode and remove/hide the options that should not appear.
The XAML
<ComboBox x:Name="RecordType" Grid.Column="1" Grid.Row="1" Width="150" HorizontalAlignment="Left" SelectedValue="{Binding Path=RecordTypeID,TargetNullValue=0}"/>
The code behind - and my (feeble!) attempts so far
foreach (ComboBoxItem item in this.RecordType.Items)
{
if (IsApplicable(item.Content.ToString()) == false)
{
item.Visibility = Visibility.Hidden;
}
}
(NOTE: IsApplicable() is a simple method that compares the string it receives to a list of the options that are allowed to appear when the form is in 'amend' mode.)
The problem
As I'm sure many of you will already know ... cannot cast object of type DTO to type System.Windows.Controls.ComboBoxItem
The question(s)
Can I get at the string values in this, or a similar way? If so, how, please?
Correct way to do this would be to apply Filter on Collection View
See Automatically Filtering a ComboBox in WPF
ICollectionView view = CollectionViewSource.GetDefaultView(comboBox.ItemsSource);
view.Filter = IsApplicable
view.Refresh(); // <-- call this whenever you change the view model
It would likely be easier for you if you bound your combobox to an ObservableCollection and then removed the items from the collection when needed.
Here is an example: http://www.tanguay.info/web/index.php?pg=codeExamples&id=304

how to bind autocomplete box to a database table column?

i am currently creating a Gridview using telerik control which displays data from the sql database which i displays through domain datasource used in wcf ria.(ADO.net entity model etc)
i want to add an autocomplete box above my radgrid where i type an name and other matchable entries are also listed.
when i click on the entry then radgrid may display whole row containing that name.
i am using silverlight 4,wcf ria,telerik controls.
please provide a sample coding idea in xaml and xaml.cs.
i tries to access telerik demos but they are not running on my system.
As an example... say you have a list of Customers, of which you want to display their names in your AutoComplete box. Further, your Grid should display all customers, and when a Name is selected in the AutoComplete box, the Selected item of the grid displays.
What you need to do is bind the SelectedItem property of the RadGridView & AutoCompleteBox. What I would do is bind the AutoCompleteBox to a property named SelectedName, like so:
<input:AutoCompleteBox ItemsSource="{Binding Names}" SelectedItem="{Binding SelectedName, Mode=TwoWay}" />
Emphasis on the 'Mode=TwoWay' - this is what will alert your code behind that the UI has changed.
In your code behind, you would create properties like this:
private string selectedName;
public string SelectedName
{
get { return selectedName; }
set
{
if (value != null)
{
var query = (from c in CustomersList
where (c.Name == value)
select c).FirstOrDefault();
SelectedCustomer = (Customer)query;
selectedName = value;
}
}
}
Notice how, when you're setting the SelectedName, you're using LINQ to determine which of the customers were selected. One pitfall here would be if you have multiple names in a list... this code only selects the first. If this is an issue, you probably should rethink your architecture..
Then for your grid, you would bind the SelectedItem like so:
<telerik:RadGridView
....
SelectedItem={Binding SelectedCustomer, Mode=TwoWay"}
....
</telerik:RadGridView>
In your code behind, you'd create this property:
private Customers selectedCustomer;
public Customers SelectedCustomer
{
get { return selectedCustomer; }
set {
selectedCustomer = value;
MyGridView.SelectedItem = selectedCustomer;
}
}
Something like that should get you started.
SS

WPF Toolkit datagrid /doesn’t refresh data

H I use SQL CE and LINQ. I bind property typeof Table on ItemSource of Datagrid control from WPF Toolkit.
Something like this.
public Table<TestNick> MySource
{
get { return _tab; }
set
{
_tab = value;
NotifyPropertyChanged("MySource");
}
}
<Controls:DataGrid Name="Dg"
ItemsSource="{Binding Path=MySource, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="0"/>
I retrieve data from DB with LINQ:
const string connStr = #"Spiri_SQL_CE_DB.sdf";
_dc = new Spiri_SQL_CE_DB(connStr);
MySource = _dc.TestNick;
If I add a breakpoint on last line I see all values from tables TestNick, but it doesn’t load this data in DataGrid.
What is bad?
EDITED:
I check the ItemSource of DataGrid control in code behind, the item source is correct but I see in DataGrid (view) "old data".
So binding must be correct, problem is that DataGrid control doesn’t refresh data.
Make sure datagrid autogeneratecolumns is true
While running check the output window if there are any binding issues
Another trick is to put a button on the view and write a code behind function on click of that button to debug whats the datagrid itemsource, if its empty try to invoke viewModel/Model's getDatagridData function and then see if it loads, in case it loads that means your NotifyPropertyChanged is not yet functional

WPF databinding to System.Data.Linq.Table<T>, how to update the interface?

I have this combo bound to a linq table.
Is there a lightweight way to update the UI (combo values that are displayed to the user) when I insert a new record in the linq table?
Basically from what I understand I should have used an ObservableCollection, but I don't want to copy the data back & forth from the linq table to that collection, I only want to have data in the linq table.
Is that possible?
EDIT
OK Here is what i have done (and still it doesn't work):
private ObservableCollection<Categories> m_Categories;
private ObservableCollection<Categories> Categories
{
get
{
return m_Categories;
}
}
in the XAML i have:
<ComboBox Name="cmbCategory"
ItemsSource="{Binding Categories}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
/>
So, pretty simple.
//if i have a new category, i want to update the combo's content
if (frmEditCategory.ShowDialog() == true)
{
//get the new category and add it to the ObservableCollection
LibraryDataStore.Instance.Categories.ToList().ForEach(p =>
{
if (!m_Categories.Contains(p))
{
m_Categories.Add(p);
}
});
//update the target? is this correct?!
BindingExpression be = cmbCategory.GetBindingExpression(ComboBox.ItemsSourceProperty);
if (be != null)
be.UpdateTarget();
}
Checked with the debugger, m_Categories contains the new category, but it doesn't show up in the combo.
Also, do you know any good tutorial or blog post about combo binding?...
Thank you in advance
What you are asking for is not possible. You need a mediator of some sort, and you have already identified the correct one- ObservableCollection. You have to move the Linq data somewhere if you want your user interface to be notified when it changes. You should have one ObservableCollection, which you add your Linq data to, and then you should bind the combo-box to the ObservableCollection rather than directly to the table. That is the simplest, most light-weight solution you can create and still receive automatic change notifications.

Resources