How to refresh the UI in a metro app? - c#

I'm using this code in a XAML page:
<TextBox ItemsSource="{Binding Posters, Converter={StaticResource collectionToFirstElementConverter}, Mode=TwoWay}" />
Posters is an ObsevableCollection and I'm using a converter where takes the collection and gets the first element of it.
As I'm using async procedures, where the textbox receives the object, this one has no elements (Count=0), and calls the converter.
I'm trying to update the textbox everytime the property add new elements, but not calls the converter.
I remember that in Silverlight or WPF, exists SourceTrigger or UpdatePropertyChanged, but in WinRT I can't see this mode.

The easiest way to achieve that would be to modify your view model containing the Posters property accordingly. I can see two ways to go about it (both asuming that your view model implements INotifyPropertyChanged):
Add an event handler to Posters.CollectionChanged and inside it raise INotifyPropertyChanged.PropertyChanged for Posters.
Add another property FirstPoster returning the value of the first element in Posters. In the view model add an event handler to Posters.CollectionChanged and inside it raise INotifyPropertyChanged.PropertyChanged for FirstPoster. This way you don't even need the converter.
I personally like the second approach better.

Related

C#/WPF Bind to Earliest Date in Collection

I've got an ObservableCollection<LegEventItems> that holds items. I have a timeline in which I need to get the Earliest date in this collection for the period start property. I'm not sure what the best way to do this is.
I'd like to do this all in xaml (with the exception of creating properties or converters) if possible. I've tried to create a converter and use it like such:
{Binding Source={x:Static cs:CurrentData.LegEventItems}, Converter={StaticResource earliestDateCnv}}
The issue is the values don't get updated in the converter. It gets called once when the timeline first renders, however when more items get put/removed from the observable collection, it doesn't update.
I've incorporated INotifyPropertyChanged on the LegEventItems already. Any idea?
Found a solution. I'm subscribing to the CollectionChanged event in my user control class (with the timeline). When that fires, I update the periodStart and periodEnd properties. Wish I was able to use pure xaml like I had said in the question, however this is a solution I'm fine with rolling with.

Updating a parent collection based on a child binding in UWP

I have a collection of items, which I have bound to an ItemsControl:
<ItemsControl ItemsSource="{Binding ProductCategories, Mode=TwoWay}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ToggleButton IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                            <TextBlock Text="{Binding CategoryName}"/>
                        </ToggleButton>
I then have a second items collection which, in my view model, is based on a query, dependant on the above collection.
So, my requirement is to filter a list of products, based on the above category. The problem that I have is that the above binding is to a ProductCategory; so, while the set fires correctly for the 'IsSelected' property on ProductCategory, it doesn't notify that the 'ProductCategories' has changed.
ProductCategories is defined as:
public class ProductCategories : ObservableCollection<ProductCategory>
My first thought was that I could achieve this by using a DataTrigger; however, these don't seem to be available since WinRT. I could also use some kind of message notification for this, but I feel like this is something that should be achievable directly from the XAML binding.
So, my question is, is it possible to raise a notify that the parent class has changed, when the child class is changed.
DataTriggers are available in UWP using this nuget package https://www.nuget.org/packages/Microsoft.Xaml.Behaviors.Uwp.Managed
Here the link to the wiki https://github.com/Microsoft/XamlBehaviors/wiki/DataTriggerBehavior
Using this, you can invoke Command using DataTrigger binded to IsSelected.
So you're trying to filter one collection (Products?) by the selected item from another collection (ProductCategories)?
If so, you seem to be over thinking this slightly. Remove any 'IsSelected' concept from your ProductCategory class as this is display related and does not belong in your model. Then change the ProductCategories ItemsControl to a ListBox and bind the LsitBox.SelectedItem to a 'SelectedProductCategory' property in your view model as Mode=TwoWay, UpdateSourceTrigger=PropertyChanged. When the user selects an item in the ListBox, the 'SelectedProductCategory' setter will be called, at which point you can filter your second collection (remembering to call PropertyChanged if the collection doesn't support change notification).
Hope it helps.

Which Event do I need after DataGridrow is added to an ObservableCollection

I have a DataGrid and canUserAddRows=true and an ObservableCollection. I want something like a validation for the ObservableCollection. So user add a row and before it gets to the ObservableCollection, I want to check the data...
I have tried RowEditEnding-Event, but when this event is fired, the new row isn't add to the ObservableCollection at this time.
Another try is the CollectionChanged-Event fromt the ObservableCollection itself but for some reason this doesn't fire... I know I could use a validation for DataBinding but there should be a way over events, or?
I am using .NET 3.5 and WPF.
Thank you in advance.
There are several different ways to perform data validation when using WPF. None of them are particularly quick to implement. I personally tend to prefer implementing either the IDataErrorInfo or INotifyDataErrorInfo interfaces on my data items.
You can also use the ValidationRule class on your Bindings. However, for a complete validation example with the DataGrid, you can also refer to the How to: Implement Validation with the DataGrid Control page on MSDN.

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.

Changing the standard behavior of a TextBox?

I have an application that declares textboxes in various places, like in styles and datatemplates, and now I'm in a situation where I need to change every textbox's standard behavior for getting and losing focus.
What's a good way to do this?
I was thinking of two solutions: one is to derive a new class from TextBox, which I understand is generally frowned upon. The other is to create some kind of style that uses EventSetters, but since the styles and datatemplates in my application don't have codebehind files I donno how an event will find the appropriate event handler.
You can create a style that applies to all TextBoxes using the Key property as follows:
<Style x:Key={x:Type TextBox}>
...
</Style>
You can then modify the Template property of the TextBox and use Triggers to add special behavior to the OnGotFocus and OnLostFocus events.
Based on your feedback, I'd recommend an attached behavior used as follows:
<TextBox b:TextBox.SuppressOnFocus="True"/>
The attached behavior implementation would simply attach to GotFocus and LostFocus and clear/reapply the binding as appropriate.
Under normal circumstances, I, too, would frown upon subclassing TextBox. In this case, since you are changing the behavior of the TextBox, a subclass may be your best option.
If you are going to use this functionality in only one project then you can create UserControls which has a TextBox and access the the OnFocus properties. You can also make a Custom WPF Control which derives from a TextBox and then implement the LocusFocus event.
I have used the same approach to create a User Control TextBox which performs validation:
http://www.highoncoding.com/Articles/578_Creating_WPF_TextBox_UserControl_to_Perform_Custom_Validation.aspx

Categories

Resources