UWP: Live queries and searches with realm - c#

I'm using Realm as my main database and sync engine and my question is that how do I do live queries for search?
for example when I use
var _age= 7;
Instance.All<Dog>().Where(d => d.Age == _age).AsRealmCollection();
and bind my listview to it, I need my view to be updated when I change the _age variable. As another word, I want to have a "Dynamic" query to my database. I want my view to be updated when I want to look for "Dogs" in different ages. But when I run this query again and assign new collection to ViewModel, my view does not update.
What shall I do?
UPDATE:
Here you can get a sample code so you can reproduce this issue:
https://github.com/Mohsens22/RelamTest
Also I must tell you that IRealmCollection<T> implements INotifyPropertyChanged by default so if you add any items to the collection with a "Write transaction" the view will be updated. More info can be found HERE

I have checked your code sample and I found Dogz will be recreate with Instance.All<Dog>().Where(z => z.Age == nxt).AsRealmCollection();. So you need two way bind model.
<ListView x:Name="itemListView" ItemsSource="{x:Bind Dogz,Mode=TwoWay}">
And this is document about bind that you could refer.

Related

How to make List<Object> variable appear in DataBinding UI when using WPF in Visual Studio?

I'm in the process of learning WPF and currently exploring data binding. I have a DataGrid control on my form, and in my C# code for the form I have a List<string> variable.
I want to be able to use the Properties UI for the DataGrid in the designer to bind the List<string> to the DataGrid. I cannot figure out what I need to do or where I need to look in the UI to do this.
This is what I am doing:
Click my DataGrid in the UI designer to make it the active control.
Move to the Properties window.
Scroll down to the ItemsSource property.
Click on the field and the UI with Source, Path, Converter and Options pops up.
And when I get to this point I no longer know what to do.
I do not want to accomplish this by writing/modifying XAML. I want to know how it works using the UI.
Having never used the designer before, I can't be totally sure (your use case isn't quite clear either).
That being said, in my designer you
Set the "Binding Type" to "Data Context"
Select the "Custom" text box (needed for me because it doesn't see my DataContext)
Type the name of your property in the "Path" field (you can only bind to Properties)
Hit OK.
Note that this is the same as writing in XAML:
<DataGrid ItemsSource="{Binding MyItemCollection}"/>
<!-- or --!>
<DataGrid ItemsSource="{Binding Path=MytItemsCollection}"/>
There's a reason no one uses the designer....
The other options are more "advanced" binding concepts that you don't normally use on ItemsSource properties.
Note that DataGrid is a poor choice for displaying strings. ListView or ListBox are much better choices, as they don't assume your information has multiple pieces (like DataGrid does).
I understand not liking XAML, as it really intimidated me at first, but I will quickly say that it is a powerful tool. I am not sure how to do it through the designer, but in C# let's say you name your DataGrid 'myDataGrid' and your List is named 'stringList'. It is as simple as the following:
myDataGrid.ItemsSource = stringList;
and the data grid is now bound to your string list.
Thanks for asking the question! The properties window is so underrated.
First you must set the DataContext.
It's in the common section of the properties window. Set the data context to whatever view model you need. If you don't have a VM and the List is in the code behind, set the data context to relative source self.
Next in the Path write the name of your List.
Also, you may want to use ObservableCollection instead of List so your objects are updated in the UI as they change.

How to current logged in user's id to textbox

Im trying to get data from first row in datagrid in c# wpf app but i cannot figure out the code.
Can somebody help me?
I tried WF app code but it doesn't work because there's not function of .Rows
return Convert.ToInt32(dataGridView1.Rows[dataGridView1.CurrentRow.Index]
.Cells[0].Value.ToString());
Thanks
UPDATE:
Im trying to get current's logged in users id to display in textbox, so i can use it to make a reservation later and join two tables.
Also can somebody help write SQL statement that joins two different id's (user's ID and id of the book that user is buying into a new table called "reservations"
Can somebody help me?
Since others have already posted a potential workaround for your problem, I'll go ahead and explain the proper solution:
Delete all your code and start all over.
WPF is NOT winforms, and if you're working with WPF, you need to leave behind any and all notions you got from the traditional approach and understand and embrace The WPF Mentality.
Basically, you don't "get data from a DataGrid" in WPF, simply because UI is NOT Data.
This means that the data you're trying to obtain must not be stored by the UI to begin with. Instead, you need to create a proper Data Model and use DataBinding to populate the UI with such data from the DataModel.
The responsibility of the UI is to show data, not store it. This is an important mindshift from the traditional approach where you would manually populate the UI with data and then retrieve the data from the UI.
WPF Two-way DataBinding capabilities make it easier to implement such scenarios in a clean, decoupled way.
Say you have a User class which has a Name and an Id property:
public class User
{
public int Id {get;set;}
public string Name {get;set;}
}
first step to show this in a DataGrid is to create a proper ViewModel that contains a collection of this class:
public class ViewModel
{
public ObservableCollection<User> Users {get; private set;}
public ViewModel()
{
Users = new ObservableCollection<User>();
//... Populate the collection here.
}
}
then you will use this class as the DataContext of your UI:
//Window's constructor
public MainWindow()
{
InitializeComponent();
//Here we set the DataContext:
DataContext = new ViewModel();
}
Finally, you create the proper DataBindings in XAML:
<DataGrid ItemsSource="{Binding Users}"
x:Name="DataGrid"/>
<!-- ... -->
<TextBox Text="{Binding SelectedItem.Id, ElementName=DataGrid}"/>
Notice how I'm using an ElementName binding to bind the TextBox directly to the DataGrid.
This is the preferred, professional approach to WPF. I suggest that you read all the linked documentation and try to familiarize yourself more with this approach.
If you're populating your DataGrid with a List<SomeObject>, for example, try this:
var row = ((SomeObject)DataGrid1.Items[0]);
Just cast the item back to your class type, then access the properties on it. You may want to do a check to make sure there's something displayed in the grid before accessing Items[0].
You can sort different columns in your grid, and this will always grab the record displayed at the top.
Edit, after seeing the following comment:
When I click on first row in DATAGRID, this function should/must display user's ID in the textbox below data grid. That is all.
You can bind directly to your grid, to display the property you want from the currently selected row.
<DataGrid x:Name="DataGrid1" />
<TextBox Text="{Binding ElementName=DataGrid1, Path=SelectedItem.UserId}" />

Modify selected RibbonComboxBox item by code

I try to modify selected item by code of a RibbonComboBox:
<r:RibbonComboBox x:Name="RibbonComboxBoxEditEnemyProjectiles" Label="Projectile" SmallImageSource="img/history16.png">
<r:RibbonGallery SelectedItem="{Binding Path=iSpriteIdx}" >
<r:RibbonGalleryCategory ItemsSource="{Binding oProjectiles, Source={StaticResource GameInfos}}" />
</r:RibbonGallery>
</r:RibbonComboBox>
I try 2 ways :
RibbonGalleryEditProjectileSprite.SelectedItem = GameData.oSprites[ idx ];
RibbonGalleryEditProjectileSprite.SelectedValue = GameData.oSprites[ idx ];
This ways don't work. What is a correct way to do that ?
Thanks
If you search this website before you post questions, you can find good answers... Take a look at this post and this post.
UPDATE >>>
The How to set SelectedItem on a RibbonComboBox using MVVM? post that I gave you a link for has a complete solution for you. Basically the answer is this:
Whatever object that you set as the RibbonGallery.DataContext should have a collection property to bind to the RibbonGalleryCategory.ItemsSource property and a property of the same type as the collection items to bind to the RibbonGallery SelectedItem property.
Let's say that your selected item property is called SelectedItem. You will then be able to set the SelectedItem property of the object that you set as the RibbonGallery.DataContext to an item from the collection and the binding will change the selected item in the RibbonGallery UI.
Note that if you are using objects as your gallery data types (as opposed to primitives like string, etc.), then this will only work if you set your SelectedItem property to an actual item from the collection and not just one with the same values. This can be easily achieved if your data object has a property with unique values by the following:
DataContextData.SelectedItem = DataContextData.CollectionData.Where(d => d.Id ==
itemToSelect.Id).Single();
If that still hasn't helped, I did a quick search online and found a complete solution that you can download and examine at your leisure in the How do I add Galleries to my Ribbon? post at 'The official blog of the Windows Presentation Foundation Team'. It shows a good example of the method that I just described.

How to forbid automatic databinding on validation error

I'm creating a simple database application in C# WPF using MVVM as Relay Commands and databinding. For in-memory storage of database content I use ObservableCollection, which is binded to the Datagrid as follows:
<DataGrid ItemsSource="{Binding Path=Softwares, Mode=OneWay}" SelectedItem="{Binding Path=SoftwareSelection, Mode=TwoWay}">
when the item is selected user can chose to edit it. For editation a form is opened with a bunch of textboxes with the data of given entity. All the fields are validated using IDataErrorInfo, unless all textboxes are valid, the ok button is not enabled, and therefore no changes can be saved to the collection and to the database.
Here is how the example textbox looks like:
<TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
But the tricky part is, in case I change some values in textboxes and then close the window, the new values are propagated to the ObservableCollection, which I don't want to. Do you have any idea, how to prevent such behaviour? I would like the databinding work only after clicking the button. Otherwise the databindng works well, so as the button (dis/en)abling and reflecting changes to the database and to the collection after clicking. Both views are serviced by different ViewModels, data between views are passed by firing events.
I tried to add to the DataGrid UpdateSourceTrigger=Explicit to the ItemsSource binding, but didn't help. Perhaps, I'm missing some application logic?
Thank you very much for your help.
This is where most WPF developers make mistakes of assumptions!
In MVVM dirty data can be stored in the ViewModel and that's what the layer of VM is for! It mimics the View from Model's perspective and because View is in error, the ViewModel would also be in the error. Thats perfectly valid.
So having said that, the question remains
How will you NOT allow the temporary / dirty data to flow to your
ObservableCollection?
Two ways...
If your ObservableCollection is specific to your model class (say MyItem) then if your Model class (MyItem) is an Entity class \ DAL class \ NHibernate class create a wrapper of MyItem class called ViewModelMyItem and then instead of ObservableCollection<MyItem> use ObservableCollection<ViewModelMyItem>.
This way dirty data from your View would be inside ViewModelMyItem and it can only be legitimately flown back to your model class (MyItem) ONLY when Save button is clicked. So that means in Save Command's Execute() delegate you can copy \ clone the ViewModelMyItem's properties into Item's properties, if validations in ViewModelMyItem are fine.
So if Item is an EntityType class / NHibernate class / WCF client model class, it would always only valid data as ViewModelMyItem is filtering the temporary / dirty information upfront.
You could use Explicit binding model. It stops the TwoWay data to flow back to the sorce Item unless BindingExpressions.UpdateSource() is explicitly called.
But according to me, this defeats MVVM in straightforward way because ViewModel will not have what UI is showing! Still however you can use *Attached Behavior * to govern explicit binding by staying in MVVM space!
Let me know if this helps!
You're better off putting the code into the domain object's property setter. Then synchronize with the visuals by triggering the NotifyPropertyChanged handler.
More on this topic:
http://msdn.microsoft.com/en-us/library/ms743695.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
Setting the Binding Mode to Explicit should require you to call the binding expressions UpdateSource() method to send changes back to your model. Because you only mentioned that you set Explicit on the DataGrid's binding, I'm guessing you only need to make sure that you have that mode explicitly set on any property that is being bound directly back to your model. Such as your TextBox's Text Binding, in the case above. That will likely fix your problem but require you to call UpdateSource() on each target's BindingExpression one way or another.
If you're using one of the mainstream ORM's (EF, Linq to SQL, etc), then chances are your Entities automatically implement INotifyPropertyChanged and INotifyPropertyChanging. Because you are sharing a reference to your single instance, all changes in your edit will be reflected in your main view and anything else Binding to that instance. As a dirtier alternative, you can just create a separate instance of the same type and manually copy the values back over when the window's dialog result is true.
The first approach requires you to manually update the bindings, the second approach requires you to manually update the values from the Edit's instance.
With some more code, I can help with your specific approach.

Silverlight 3 - Filtering an Observable Collection

Is there a way to filter/sort an observable collection and still keep the notifications?
I have looked around and I found CollectionViewSource which filters and sorts the collection as I require but when the an items property in which the filter relies changes at the source collection it does not refresh the filter.
Basically i require a view of the original collection that when a property of an item in the view changes it updates the source and when the source changes it updates the view. Is there any class that provides this functionality in silverlight 3?
Does ObservableCollection with TwoWay binding not work? Can you elaborate your example with some code to show the issue in more detail?
I would suggest using the Bindable.Linq library, it hasn't been updated for a while and there is a bug with the Union operator. But for linq style filters it works great.
heres a quick example, assuming this is in the codebehind of a silverlight user control with a listbox named people:
using Bindable.Linq;
...
ObservableCollection<Person> data = new ObserableCollection<Person>{.... fill in};
people.ItemsSource = data.AsBindable(Dispatcher).Where(p => p.FirstName.Equals("steve"));
data.add(new Person("steve"));
if you do this steve should show up on the list. I have found this library very useful and if you download the sample projects from codeplex it shows more advanced examples.
Hope this helps.
There are several other similar projects

Categories

Resources