I'd like to use the ItemsSource property from a particular element as one of the bindings in another element's MultiBinding. Here's what I have so far:
<Label>
<Label.Content>
<MultiBinding Converter="{converters:myMultiValueConverter}">
<Binding Path="PageIndex" />
<Binding ElementName="anotherElement" Path="ItemsSource"/>
</MultiBinding>
</Label.Content>
</Label>
This works once (when the ItemsSource is initially set), but the binding fails to update when the ObservableCollection bound to the original element's ItemsSource property has items added or removed. Is this kind of binding possible?
Add a dummy binding (- you don't need the value -) like this to force the MultiBinding to be reevaluated:
<Binding ElementName="anotherElement" Path="ItemsSource.Count"/>
Edit: Just noticed a flaw: If you move items that would not register if that does not change the Count property in-between, maybe this is relevant for you. In that case you could bind to your own dummy for which you can fire change notifications upon CollectionChanged (not all that clean in any case though).
You might want to consider HighCore's suggestion, a get-only property that returns the calculated value for which you manually fire PropertyChanged in all places that it depends on is usually quite convenient.
Related
I am using the MVVM pattern and in my view I have this dataGrid:
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource myMultiValueConverter}">
<MultiBinding.Bindings>
<Binding />
<Binding ElementName="ThisControl" Path="DataContext.MyObservableCollectionInViewModel"/>
<Binding ElementName="thisControl" Path="DataContext.ControlType"/>
<Binding ElementName="ThisControl" Path="DataContext.ExternalItems"/>
<Binding Path="Componentes.OneProperty"/>
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
And my view model has this code:
private void myMethod()
{
MyObservableCollectionInViewModel.Clear();
MyObservableCollectionViewModel.Add(new myType());
}
When I execute the method MyMethod(), if a I am not wrong, the multi value converter would be run, because the ObservableCollection implements INotifyPropertyChanged when I add or remove items, but in this case does not work.
However I have another ObservableCollection for the DataSource of my dataGrid and it works as it's expected, refresh the dataGrid when I add or remove items from the ObservableCollection.
However, if in myMethod I do this:
private myMethod()
{
myObservableCollectionInMyViewModel.Clear();
myObservableCollectionInMyViewModel.Add(new MyType());
myObservableCollectionInMyViewModel = new ObservableCollection(myObservableCollectionInMyViewModel);
}
It works, so the view is notified when I create a new ObservableCollection, not when I add or remove items from the actual ObservableCollecion.
Yes, that's the correct behavior.
The reason the ObservableCollection Add/Remove works for ItemsControl, ListBox, DataGrid etc, is that they are explictly taking care of the behavior you are describing, that is not WPF specific, eg: it doesn't have to do with the actual binding of ItemsSource.
What happens under the cover is, all these controls(ListBox, etc..) are inheriting from ItemsControl which ultimately wraps ItemsSource into CollectionView, which will take advantange of INotifyCollectionChanged interface, if possible. That's how it knows / keeps up.
The "work-around" I've used successfully:
A) Just use property changed or do the swap as you've done (this might, or might not work - I don't exactly remember, but WPF might have explicit check if the actual value has been changed, in this case: it hasn't):
myObservableCollectionInMyViewModel.Clear();
myObservableCollectionInMyViewModel.Add(new MyType());
RaisePropertyChanged(() => myObservableCollectionInMyViewModel);
B)
myObservableCollectionInMyViewModel =
new ObservableCollection(new List<MyType>{
new MyType()});
C) Bind against .Count, as ObservableCollection will notify when that changes.
<Binding ElementName="ThisControl"
Path="DataContext.MyObservableCollectionInViewModel.Count"/
D) Create a new converter which will be able to listen all the events(INotifyPropertyChanged and INotifyCollectionChanged) events, which then will trigger multi converter updates.
<Binding ElementName="ThisControl"
Converter="{StaticResource observableConverter}"
Path="DataContext.MyObservableCollectionInViewModel"/>
I've created a multivalueconverter that I'm binding a telerik:RadMenuItem's visibility property. This right-click menu is inside of an appointment that goes onto a Telerik calendar control. I want to pass the ControlID (which is an attached property from the framework I'm using) into the IMultiValueConverter that I've made as a parameter. So, I want to pass in the Guid (which comes in as the second value in an object array in the converter) and then cast it something to get the value so I can do my evaluations. WPF isn't my strong suit and after trying a lot of things I can't seem to get the binding wired up.
<telerik:RadMenuItem Header="Cancel" x:Name="CancelMenuItem"
Click="RadMenuItemCancel_Click"
myframework:BaseWindow.ControlID="e5c25731-e30e-472e-a5d7-ab190348a7cb">
<telerik:RadMenuItem.Visibility>
<MultiBinding Converter="{StaticResource SecurityEnumToVisibilityConverter}">
<Binding Path="Appointment.AppointmentType" />
<Binding ElementName="CancelMenuItem" Path="myframework:BaseWindow.ControlID" />
</MultiBinding>
</telerik:RadMenuItem.Visibility>
</telerik:RadMenuItem>
What am I missing here in that second Binding tag to pass in the contents of ControlID to my multivalue converter successfully? Thanks!
Try surrounding your path with brackets.
Path="(myframework:BaseWindow.ControlID)"
afaik this tells WPF that you are binding to an attached property
I have a single property that consists of three letters and two numbers, such as "ABC 12". The requirements for my project ask that the UI divide this into a ComboBox for the three letter combinations and a TextBox for the numerical. I can do this pretty easily using a converters to parse out the part of the string that I need.
My question is whether there is a way to implement the "ConvertBack" logic in my converter such that I can reset the property based upon the values in the two different controls.
My xaml:
<ComboBox IsEnabled="{Binding EditMode}" ItemsSource="{Binding AbbrevsList}"
DisplayMemberPath="SelectedAbbrev" SelectedValuePath="Abbrev"
SelectedValue="{Binding Row.Code, Converter=CodeAlphaConverter,
UpdateSourceTrigger=PropertyChanged}" />
<TextBox TextAlignment="Left">
<TextBox.Text>
<Binding Path="Row.Code" Converter="CodeNumericConverter"
UpdateSourceTrigger="LostFocus">
</Binding>
</TextBox.Text>
</TextBox>
Thanks.
Since WPF does not allow you to bind converter parameters, you may have to switch your approach. Instead of using converters, other answers on SO point to changing your View Model to have the logic built into two properties and binding to those or, instead of passing in the individual value to the converter, you pass in the entire object.
I've currently got XAML code like this:
<ListView Name="fileLV" SelectionMode="Extended" ItemsSource="{Binding path=DataContext.SelectedAsset.Files,ElementName=selectionView,IsAsync=True}"/>
That "Files" property takes fifteen seconds to return. The whole time the user is wondering what's going on. I've seen some other code to show the fallback value or use multiple bindings, but those don't rely imply "leave this control alone" like an hourglass over that control would imply.
What I want is to be able name a binding and then bind some other properties to that binding's IsBusy property. I want a trigger to change the cursor on that listview while his binding is busy. Is there any existing WPF framework help for this?
I don't know of any built-in, out-of-the-box solution but there sure are ways to make a nice experience out of it.
I will give you the quick idea of how I would build this and if you need I can come up with the code as well:
Create a "LoadingItem" DataTemplate that would show an progress bar of some kind as an item of your list
Create a "DataTemplateSelector" to switch between the LoadingItem
and the RegularItem of your list.
In your Files property, clear the collection and add an item that
will be shown as LoadingItem (depends on how you built your
DataTemplateSelector logic. Start another thread to scan for files
and fill a return the results in a temporary collection
(BackgroundWorker). When the method returns, you are on the UI
thread again, clear your ItemsSource collection again and fill it
with the results.
For this do not use IsAsync. On the Property use a BackGroundWorker. First return a source with a "working message", start BackGroundWorker, then on the callback supply the real source and call NotifyPropertyChanged. You can even have a progess bar.
I was able to make the DataTemplateSelector work. One caveat was that all the bindings for the ListView need to be enumerable. In my control I added a resource like this:
<UserControl.Resources>
<x:Array x:Key="LoadingTemplate" Type="DataTemplate">
<DataTemplate>...my daisy code...</DataTemplate></x:Array>...
Then I changed my binding to look like this:
<ListView.ItemsSource>
<PriorityBinding>
<Binding Path="DataContext.SelectedAsset.Files" ElementName="selectionView" IsAsync="True"/>
<Binding Source="{StaticResource LoadingTemplate}" />
</PriorityBinding>
</ListView.ItemsSource>
Then I installed this template selector:
public class OverridableDataTemplateSelector: DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return item as DataTemplate ?? base.SelectTemplate(item, container);
}
}
I have a ComboBox whose ItemsSource is bound to an ObjectDataProvider that has its IsAsynchronous property set to true. Inside the method that loads the data , I put a Wait for 10 seconds, to simulate a long loading time for this data.
The Asynchronous loading works great - the entire window is still responsive, and after 10 seconds I see the ComboBox dropdown populated.
I would like to alert the user that this specific ComboBox is loading data, during that 10 second wait time. Something like a progressBar in the background of the control, that is enabled only while a certain 'isLoading' property or whatever is set to true. Is it possible to accomplish this?
Thanks.
this looks like the Priority Binding could be a solution for you
<ListBox>
<ListBox.ItemsSource>
<PriorityBinding>
<!-- highest priority sources are first in the list -->
<Binding Path="LongLoadingCollection" IsAsync="True" />
<!-- this contains only one item like "loading data..." -->
<Binding Path="LoadMessage" IsAsync="True" />
</PriorityBinding>
</ListBox.ItemsSource>
</ListBox>
here is an good tutorial for Priority Bindings
http://www.switchonthecode.com/tutorials/wpf-tutorial-priority-bindings
or take a look at msdn
http://msdn.microsoft.com/en-us/library/system.windows.data.prioritybinding.aspx
hope this helps
It doesn't appear that the ObjectDataProvider has any properties to say when it is and isn't retrieving data.
It depends on your architecture, but you could expose properties that give a "load state" to your object that contains the method that loads the data. Then you could bind a progress bar or other "Please Wait..." kind of UI to that new state property.