Combobox with collection view itemssource does not update selection box item on changes to the Model - mvvm

Sorry for the earlier lengthy post. Here is my concise (!) description.
I bind a collection view to a combobox as a itemsSource and also bind its selectedvalue with a property from my view model. I must keep IsSynchronizedWithCurrentItem="False".
I change the source list ofr the view and then refresh the view. The changed (added, removed, edited) items appear correctly in the item list of the combo. But problem is with the selected item. When I change its property which is also the displaymember path of the combo, the changed property value does not reflect back on the selecton box of the combo. If you open the combo dropdown it appears correctly on the item list but not on the selection box.
Now if I change the combobox tag to Listbox in my XAML (keeping all attributes as it is) then when selected item's displaymember property value is updated, the changes reflect back on the selected item of the list box .
Why this issue?
Just FYI:
My View Model has properties EmployeeCollectionView and SelectedEmployeeId which are bound to combo as ItemsSource and SelectedValue resp. This VM implements the INotifyPropertyChanged interface.
My core employee class (list of which is the source for the EmployeeCollectionView) is simply a Model class without INotifyPropertyChanged.
DisplayMemberPath is "Name" property of employee Model class. I change this by some means and expect the combo selection box to update the value.
I tried refreshing ther SelectedEmployeeId by setting it 0 (where it correctly selects the dummy "-- Select All --" employee entry from itemsSource) and old selected value back. But no use. The old value takes me back to the old label. Items collection has latest entry though.
When I make combobox's IsEditable=True before the view's refresh and after refresh I make IsEditable=False then the things work out correctly!
But this is a patch and is unnecessary.
Thx
Vinit Sankhe

Your points #2 and #3 are why this isn't working. When the ComboBox has an item selected, it displays in the box the Employee.Name property. You state in #2 that Employee does not implement INotifyPropertyChanged and in #3 you are changing Name and expecting it to update in the ComboBox. But the ComboBox has no idea that the property changed so its displayed value will not change.
I've put together a very simple example that will demonstrate. If you comment out the PropertyChanged event you'll notice that clicking the button no longer has an effect on the UI.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="WidthAndHeight">
<StackPanel>
<ComboBox ItemsSource="{Binding}" DisplayMemberPath="Name" SelectedIndex="0" Width="150" Height="25" />
<Button Content="Change" Width="75" Height="25" Click="button_Click"/>
</StackPanel>
</Window>
And the code behind...
public partial class MainWindow : Window
{
private ObservableCollection<Thing> things;
private Queue<string> words;
public MainWindow()
{
// some dummy data
string text = "Lorem ipsum dolor sit amet consetetur sadipscing elitr sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat sed diam voluptua";
words = new Queue<string>(text.Split(' '));
things = new ObservableCollection<Thing>();
things.Add(new Thing { Name = words.Dequeue() });
things.Add(new Thing { Name = words.Dequeue() });
things.Add(new Thing { Name = words.Dequeue() });
DataContext = things;
InitializeComponent();
}
private void button_Click(object sender, System.Windows.RoutedEventArgs e)
{
things[0].Name = words.Dequeue();
}
}

Related

How do you bind MAUI PIcker to a ViewModel?

Here is my .xaml
<Picker x:Name="Title" SelectedItem="{Binding Title, Mode=TwoWay}" ItemsSource="{Binding Titles}" ItemDisplayBinding="{Binding Text}" Title="Title" />
<Entry x:Name="Name" Text="{Binding Name}" Placeholder="Name" />
Bound to a View Model .cs which looks like this
public class Person
{
public string Name { get; set; }
public string Title { get; set; }
List<SelectListItem> Titles = new(){
new SelectListItem { Text = "Mister", Value="Mr" }
new SelectListItem { Text = "Doctor", Value="Dr" }
...
}
}
Containing this data
Person person = new() { Name = "Bill Jones", Title = "Mr" };
So the picker displays the list just fine. But I have two issues.
How do I get the picker to display the correct entry when it loads, in this case, default to Mr
If I change the value in the picker, how do I get the bound ViewModel to take on that entry? (Remember I want to store the selected value, not the displayed value). I know it works with a simple string list, but that's not what I want here.
It almost feels like I need an ItemValueBinding property or something like that. (Obviously, I just made that up)
I've seen quite a lot of complicated code using INotifyPropertyChanged and doing clever bits of code in the SelectedIndexChanged event. But if I have a lot of pickers on my page that seems like a lot of code I have to write.
Is there a simpler way that I might have missed, to achieve both requirements?
If you want to set a default value of your picker, you could try like this:
Title.SelectedIndex = 0; // That means the picker chooses the first item. PickerIndex is 0-based
In your ViewModel , change Title property
public string Title {get; set;}
to this:
public SelectListItem Title {get; set;} // This will get selectedItem instead of just a Text
You could use BindingContext to bind Entry with Picker. Here i give you an example:
<Picker x:Name="Title" SelectedItem="{Binding Title, Mode=TwoWay}" ItemsSource="{Binding Titles}" ItemDisplayBinding="{Binding Text}" Title="Title"/>
<Entry x:Name="Name" BindingContext="{x:Reference Title}" Text="{Binding SelectedItem.Text}" Placeholder="Name"/>
In the above code, the x:Reference markup extension is required to reference the source object, which is the Picker named "Title". When the picker value changed, it also changed Entry's Text.
For more information, you could refer to Basic bindings and Picker.

Group of combobox dynamically in ZK

I am totally new in ZK. I need to create N combobox with their labels dynamically and populate them. I already populate a combobox with its id, but as there can be many combobox I should not know their ids, so It does not solve my problem.
I need to add N combobox, their labels and populate them dynamically. Is there any way to create that group of combobox and set them dynamically? Any ideas?
The code bellow works to populate the combo already knowing its fixed id.
//In this example I assume I have a label and a combobox. But could have 0 to N of them.
private Label lblComboMetadatos;
private Combobox cmbMetadatos;
//THEN
if (cmbMetadatos.getItemCount() == 0) {
lblComboMetadatos.setValue(trdMetaTipoDocumental.getNombreMetadato()); //Here I set the name of label but I should really can not know how many of them could be. There may exist 0..N
for (TrdMetadato trdMetaDato: trdMetaTipoDocumental.getTrdMetadatos()) {
String enumValores = trdMetaDato.getValoresEnumerado(); //Here I set the values of a combobox but I can not know how many of them could be. There may exist 0..N
cmbMetadatos.appendItem(enumValores]);
}
}
<zk>
<window id="idWindow" title="nameWindow" apply="controller.java" border="normal" closable="true" sizable="true" maximizable="true" maximized="true" height="85%" width="150%" style="overflow:auto;">
<!-- CONTINUES -->
<groupbox>
<hlayout>
<label id="lblComboMetadatos" />
<combobox id="cmbMetadatos"></combobox>
</hlayout>
</groupbox>
<!-- CONTINUES -->
</window>
</zk>
This question is very similar to your last question. You should wire the parent container (hlayout in this case) to your controller and then create the components there.
#Wire
private Component container; // your hlayout
#Override // This method should be specified by a composer super class
public void doAfterCompose(Component comp) throws Exception
for (<count an index or loop over data>) {
hlayout.appendChild(new Label("Hello World");
Combobox cb = new Combobox();
// append Comboitems
cb.addEventListener(Events.ON_SELECT, ...);
hlayout.appendChild(cb);
}
}
If you used MVVM, you could use children binding to create the components in zul.

WPF Radio button value and the label text

I am trying to relate the label text to the radio buttons value e.g. if radio is checked, then the label text is "x". If not, it's "y".
In my XML:
<RadioButton x:Name="radio1" Content="Option1" GroupName="Group1" IsChecked="{Binding BoolValue, Converter={StaticResource BooleanConverter}, ConverterParameter='true', Mode=TwoWay}" />
<RadioButton Content="Option2" GroupName="Group2" IsChecked="{Binding BoolValue, Converter={StaticResource BooleanConverter}, ConverterParameter='false', Mode=TwoWay}"/>
...
...
<Label Content="{Binding LabelText, UpdateSourceTrigger=PropertyChanged}" Width="70"/>
In the code:
(The _shape is bind to the radio button IsChecked;)
private bool _boolValue;
public bool BoolValue
{
get { return _boolValue; }
set
{
_boolValue= value;
PackLengthLabel = (_boolValue == true)? "x" : "y";
OnPropertyChanged("BoolValue");
}
}
And the label text property:
private string _labelText;
public string LabelText
{
get { return _labelText; }
set
{
_labelText = value;
OnPropertyChanged("LabelText");
}
}
The problem is that the changes don't affect the label text - it is the same all the time, no matter which checkbox is checked. The boolean value and the text value are changing (checked in the setters). I've also checked if the label is trying to get the _labelText from the getter but it doesn't. I also tried different binding modes, but the text was all the same.
The only way it affects the other controls is by binding directly to the other properties e.g.:
IsEnabled="{Binding IsChecked, ElementName=radio1}"
Edit1:
I can get it working in two ways:
setting the label content value in the View code behind, refering to the elements properties
using the code here: https://stackoverflow.com/a/23642108/3974198
But I'm still curious, why the simple getter and setter of the label text value didn't do the job.
Finally I got it. I had the property setters and getters in the View and the ViewModel. The problem was that the View had inherited from INotifyPropertyChanged, but the ViewModel didnt THOUGH in the ViewModel I could use the OnPropertyChanged, without getting any errors.

how to work with SAP UI5 xml views

I am new to SAP UI5.
Here my task is to convert javascript code to xml view. Here javascript is like:
var sHtmlText = '<strong>Aliquam erat volutpat.</strong><br>Vivamus vitae felis nec lacus ultricies dapibus condimentum quis felis.';
sHtmlText += 'Some link goes here:<embed data-index=\"0\">';
var oLink2 = new sap.ui.commons.Link("l2", {
text : "Click me",
href : "http://scn.sap.com/welcome",
title : "SAP Community Network",
target : "_blank"
});
var oFTV2 = new sap.ui.commons.FormattedTextView("otv2");
//set the text with placeholders inside
oFTV2.setHtmlText(sHtmlText);
//add the desired control to the FormattedTextView
oFTV2.addControl(oLink2);
var oCallout = new sap.ui.commons.Callout({
content : oFTV2
});
// create a sample form with two fields and assign a callout to each of them
var oLayout = new sap.ui.commons.layout.MatrixLayout({
layoutFixed : false
});
var oTextField, oLabel;
oLayout.createRow(
oLabel = new sap.ui.commons.Label({text:"First name:", labelFor:"firstname1"}),
oTextField = new sap.ui.commons.TextField("firstname1", {required:true, value:"John"})
);
oTextField.setTooltip(oCallout);
// display it
oLayout.placeAt("sample2");
While running the above code i am getting the text field with a label and input hover popup.
Now my task is to convert the above js view to XML View. I am getting confused.
Please suggest me the exact procedure (generalized manner) for converting the above JS view to XML view.
A quick (and dirty) way is to simply run your application, and when in the view you want to convert to XML, open the SAPUI5 Diagnostics screen (Ctrl-Alt-Shift S), show the Control Tree panel, select the topmost UIArea element, click the 'Export' tab on the right and click the 'Export to XML' button :)
First you need to add name space for your sap.ui.Commons xmlns:com="sap.ui.Commons" in your xml view
then write code like this
for more reference please check xml view developer guide
and example here Example
click on Expample in Master side then select on Detail Side and do show code

how to get a ViewModel from another ViewModel in ZK-Framework

I have two ViewModels in my MVVM app. the one is bind to main window and another to popup window which appears after click on the button. in the popup window I need binding to the selected entity from main window. how can I access this entity in MainViewModel from PopupViewModel?
ZK has the concept of the event queue and global commands for communication between multiple ViewModels so we can use that to pass the current selected entity to the ViewModel of a popup window.
Using this zk mvvm demo page:
(see docs)
I added to the listbox a global command which fires out the current selected reminder of the main ViewModel which needs to be shown by a popup window:
<listbox id="list" multiple="true" rows="6"
model="#load(vm.reminders)"
selectedItem="#bind(vm.selectedReminder)"
onSelect="#global-command('refresh', reminder=vm.selectedReminder)">
Then I added to the bottom of the page a popup window with a second ViewModel:
<window id="info" visible="false" width="120px" border="normal" position="parent"
apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('org.zkforge.zktodo2.ui.ViewModelPopup')"
>
You have selected <label value="#load(vm.currentReminder.name)"/>
</window>
<button label="More info" onClick="info.doPopup()"/>
</zk>
The pop up Viewmodel has a method which accepts the global command which takes the entity as a parameter:
public class ViewModelPopup {
protected Reminder currentReminder = new Reminder();
public Reminder getCurrentReminder() {
return currentReminder;
}
public void setCurrentReminder(Reminder currentReminder) {
this.currentReminder = currentReminder;
}
#GlobalCommand #NotifyChange("currentReminder")
public void refresh(#BindingParam("reminder") Reminder reminder ){
this.setCurrentReminder(reminder);
return;
}
}
So now whenever you select an item in the listbox the refresh method is fired on the popup ViewModel passing into it data taken from the main ViewModel. Whenever you hit the "More info" button at the bottom of the page to show the popup window it displays the name of the current selected entity.
The documentation which I followed to do this is at:
(docs1)
(docs2)
The instructions to run that sample app are on the readme at (Docs3)
Do you have a list of entities in your mainwindow? if that is the case, from the view model of your main window you need to put your selected entity in a map and pass it as a param for createComponents just like this:
//In the view Model of the main window
Map arg = new HashMap();
arg.put("selectedEntity", SelectedEntity);
Executions.createComponents("/myPopup.zul", null, arg);
Now in the popup view model, you simply retrieve the value of your Entity in the Init method:
//PopupView model
#Init
public void init(#ExecutionArgParam("selectedEntity") SelectedEntity newEntity) {
entity = newEntity;
}
you can notice that the string in ExecutionArgParam is the key you put in the map.