I'm using Silverlight's toolkit AutoCompleteBox control in a form where I want it to show the value bound to SelectedItem, or if it was null, then show the value bound to the Text property.
the problem is that when SelectedItem is null, it automatically clears the Text property, even when it was bound to a VM property that has a value.
here is some XAML:
<c:AutoCompleteBox
MinimumPopulateDelay="500"
ItemsSource="{Binding SuburbSearchResults}"
SelectedItem="{Binding SelectedSuburb}"
Text="{Binding SuburbText, Mode=OneWay}"
MinimumPrefixLength="3" />
First of all using Binding on Text and SelectedItem properties together ? Maybe it's not a good idea.
Its right when you use binding on SelectedItem this manages Text properties value for you.
If you use a ViewModel, I suggest you to bind one property of AutocompleteBox and just use SuburbText prop. in VM. (or just bind SelectedItem and you may use ValueMemberPath with it)
Edit 1:
//Suppose myVM.SuburbText is a local variable in VM, this shows Text prp. binding
//But I prefer Object binding with ValueMemberPath,you may use one of them
//But not both together
public string TextWillBeBound
{
get
{
if(SearchResults.SelectedItem!=null)
{
myVM.SuburbText=SearchResults.SelectedItem.TextProperty;
}
else if(myVM.SuburbText="")
{
myVM.SuburbText="Please write...";
}
return myVM.SuburbText;
}
set
{
if(SearchResults.SelectedItem==null)
{
myVm.SuburbText=value;
//with value you may create Suburb object ? and set as Selected.
//Depending on what you aim. I suggest using SelectedItem & ValueMemberPath
}
}
}
//How did I used this control before
//You can also bind SelectedItem and use ValueMemberPath as shown below.
<sdk:AutoCompleteBox MinimumPopulateDelay="500" MinimumPrefixLength="3"
Populating="AutoCompleteBox_Populating"
SelectedItem="{Binding Path=SELECTEDITEM,Mode=TwoWay}"
ValueMemberPath="DESCRIPTION">
Related
I have a WPF control inheriting from ComboBox whose ItemsSource is bound to a list of elements, and whose SelectedItem is bound to another field. I have two references to the same list in my application: one resides in my MainWindow class, and one resides in my App class.
The list of elements used as the ItemsSource is assigned to the ComboBox at the time it is created. Thus, I expect to get an ItemsSourceChanged event.
The strange thing is, if the ItemsSource is bound to the MainWindow's list, then the ComboBox becomes populated with the correct SelectedItem drawn from the bound field. However, if I bind the ItemsSource to the App's copy of the list, then the SelectedItem becomes overwritten with null due to the ItemsSourceChanged event.
Here is the XAML for the ComboBox when it's binding to the App copy of the list:
<local:TagSelectionComboBox FilteredTagsList="{Binding Path=TagsList, Source={x:Static Application.Current}}" SelectedItem="{Binding TagValue}"></local:TagSelectionComboBox>
Here is the XAML for the ComboBox when it's binding to the MainWindow copy of the list:
<local:TagSelectionComboBox FilteredTagsList="{Binding TagsList, RelativeSource={RelativeSource AncestorType=Window}}" SelectedItem="{Binding TagValue}"></local:TagSelectionComboBox>
Here is the MainWindow's property used for binding:
public ObservableCollection<Tag> TagsList
{
get { return proj.Sim.Tags; }
}
And here is the App's property used for binding:
public ObservableCollection<Tag> TagsList
{
get { return proj.Sim.Tags; }
}
So these two properties on App and MainWindow are returning the same list. Stepping through in the debugger confirms: proj.Sim.Tags contains the same list in both cases.
Why does changing from one binding source to another alter the binding behavior? Is something else going on?
I've found that if I explicitly set IsSynchronizedWithCurrentItem="True", then the behavior is the same in both cases. So it's almost like IsSynchronizedWithCurrentItem="True" is the default behavior when I use the MainWindow (RelativeSource) binding but IsSynchronizedWithCurrentItem="False" is the default behavior when I use the App (x:Static) binding.
Background: the ComboBox-derived control in this question is basically the same as YantingChen's answer for this question:
Dynamic filter of WPF combobox based on text input
I have a question regarding WPF binding using master-detail layout.
The master view contains a DevExpress GridControl with a TreeListView.
The detail view content is updated when the TreeListView selected item is changed (trough the binding).
The detail view contains just a ContentControl, with it's Content property bound to the current selected item of the TreeListView.
In order to display the detail view in a way that correspond to the type of the selected item, several DataTemplates are registered to the current application resources.
In my case, the DataTemplates are just one user control.
When the selection is changed in the master view TreeListView, the corresponding DataTemplate is correcly diplayed.
One of my detail view contains a DevExpress ListBoxEdit. The SelectedIndex is bound with UpdateSourceTrigger=PropertyChanged.
My problem is that the setter of the bound property is called with the value -1 when another item is selected in the master view.
It seems that the -1 default value is received when the control is unloaded or disposed or unbound. This screw up my view model.
Is there a proper way to avoid to be notified in the ViewModel when the control is unloaded?
[update]
The ContentControl that contains the detail view is defined like this:
<ContentControl Grid.Column="1" Content="{Binding CurrentApplicationSettings}" Margin="10,0,0,0"/>
In the corresponding view model (the SetValue method calls OnPropertyChanged):
public IApplicationSettingsViewModel CurrentApplicationSettings
{
get { return GetValue<IApplicationSettingsViewModel>(); }
set { SetValue(value); }
}
In the detail view where I have the problem, the ListBoxEdit is defined like this:
<dxe:ListBoxEdit ShowBorder="False" ItemsSource="{Binding AllLoggingLevels, Mode=OneTime}" SelectedIndex="{Binding Path=LoggingLevel, Mode=TwoWay, Converter={StaticResource LogLevelConverter}, UpdateSourceTrigger=PropertyChanged}">
<dxe:ListBoxEdit.StyleSettings>
<dxe:RadioListBoxEditStyleSettings/>
</dxe:ListBoxEdit.StyleSettings>
</dxe:ListBoxEdit>
In the corresponding ViewModel:
public LoggingLevel LoggingLevel
{
get { return GetValue<LoggingLevel>(); }
set { SetValue(value); }
}
The DataTemplates are registered by code:
public void RegisterDataTemplate(DataTemplate dataTemplate)
{
object dataTemplateKey = dataTemplate.DataTemplateKey;
if (dataTemplateKey == null)
{
throw new InvalidOperationException("The data template has an invalid key");
}
System.Windows.Application.Current.Resources.Add(dataTemplateKey, dataTemplate);
}
Thank you very much
Philippe
I have receive an answer from DevExpress support and this works for me.
"Having researched it, I found that this behavior occurs because of the internal editor's synchronization.When the editor loses its items source because of changing the focused row in the tree, it resets its properties such as EditValue, Text, SelectedItem, etc.
To prevent these properties from being synchronized, set the editor's AllowUpdateTwoWayBoundPropertiesOnSynchronization property to false."
I have an ObservableCollection of objects (e.g. Persons with First/Last Name) which I would like to display in an ItemsControl. Each Item is displayed in a custom "editor" control, which allows editing of the object's properties.
This part is working fine and fairly standard.
<ItemsControl ItemsSource="{Binding Persons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<custom:PersonEditor Person="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
However, the custom editor control also has the ability to replace the entire object is has received (rather than just editing a person's name, replace it with a new person object).
What I am looking for is a way to push this change back into the ObservableCollection. As it is now, changing the Person object within the editor does not replace the item in the list, which would be the desired outcome.
Any help would be appreciated.
If you don't have access to the custom control itself what you could try would be using a setter on a property to clear the ObservableCollection and re-add the items instead of outright replacing it.
For example:
private ObservableCollection<MyModel> _dataSource;
public ObservableCollection<MyModel> DataSource
{
get
{
return _dataSource;
}
set
{
_dataSource.Clear();
foreach(var item in value)
{
_dataSource.Add(item);
}
}
}
This would prevent the item itself from getting replaced which causes issues with ItemSources since they apparently only bind to the items property once.
I want to display a child window that contains a combobox with several values coming from one of the child window's property:
public partial class MyChildWindow : ChildWindow
{
private ObservableCollection<MyClass> _collectionToBind = // initialize and add items to collection to make sure it s not empty...
public ObservableCollection<MyClass> CollectionToBind
{
get { return _collectionToBind; }
set { _collectionToBind = value; }
}
}
How do I bind in XAML my combobox to the ComboBoxContent collection (both are in the same class)? I've tried several things such as:
<ComboBox x:Name="linkCombo" ItemsSource="{Binding Path=CollectionToBind }" DisplayMemberPath="Description">
I've only been able to bind it in the code behind file and would like to learn the XAML way to do it.
Thank you!
In this case I would use ElementToElement binding like this:-
<ComboBox x:Name="linkCombo" ItemsSource="{Binding Path=Parent.CollectionToBind, ElementName=LayoutRoot }" DisplayMemberPath="Description">
You give the Content element of the ChildWindow the x:Name of LayoutRoot (in the standard template for child window this is done for you). Hence you can bind to this named element and navigate to the containing ChildWindow by using its Parent property.
Using DataContext = this is tempting and works in simple scenarios but things can get awkward in more complex requirements when the DataContext has already been taken in this way.
You need to set the DataContext of the ChildWindow to what contains the values you'd like to bind to. In this case where you're putting the values you want to bind to on the ChildWindow itself so just put a line in the constructor assigned the DataContext to itself.
DataContext = this;
You can also do this using a RelativeSource binding in the XAML, like this:
{Binding Path=CollectionToBind, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}
However, a better way to do this would be to put the CollectionToBind in a separate class and assign it to the Window DataContext. Now both the Window and the XAML Bindings can all refer to the same class as the DataContext and you can isolate more of your logic into this class rather than putting it in the Window implementation.
I've an WPF application where tried to implement MVVM pattern and Prism 2. I have a Usercontrol which has subscribed to an event fired from another Usercontrol. I would like to toggle visibility of few child elements in the subscribing control. Events are fired properly, even I am successfully able to bind data to some elements. How do I bind Visibility or any style property for that matter with the ViewModel and change them dynamically.
You can have a boolean property in your ViewModel and bind that property to the Visibility property of your controls. Since you will be asigning a boolean value and the Visibility property is expecting a Visibility enumeration value, you will have to use the BooleanToVisibilityConverter converter to make the conversion,
<Style.Resources>
<BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" />
</Style.Resources>
<Image Visibility="{Binding Path=ShowImage,
Converter={StaticResource booleanToVisibilityConverter}}"/>
Hope this helps.
Ezequiel Jadib
Although adding a Boolean property and using a value converter works, I would recommend adding a property of type Visibility to your ViewModel, e.g.
public Visibility ImageVisibility
{
get { return shouldShowImage ? Visibility.Visible : Visibility.Collapsed }
}
The advantage of this method is you don't need to write a converter for every property you want to express in a visual way (e.g. for a stock level that turns a label red when it drops below 10, you could have a converter you use once or just expose a StockLabelBrush property from your VM)
There's a simple solution for people who run into this issue.
In your view model, create a "Visibility" property like so:
public Visibility ShowModifyButtons
{
get { return (Visibility)GetValue(ShowModifyButtonsProperty); }
set { SetValue(ShowModifyButtonsProperty, value); }
}
public static readonly DependencyProperty ShowModifyButtonsProperty =
DependencyProperty.Register("ShowModifyButtons", typeof(Visibility), typeof(FileMatchViewModel),
new UIPropertyMetadata(Visibility.Collapsed));
In your XAML, bind to it like so:
<Button Focusable="False" Content="Save" Width="100" Margin="10" Visibility="{Binding ShowModifyButtons}"/>
Now, from your view model, you can set ShowModifyButtons to Visibility.Collapsed or Visibility.Visible as needed.