I'm a newbie in these subjects of Xamarin, but have been able to built a good amount amount of features in a personal project to a local Bodyboarding Association that I'm doing for learning purposes.
But got stuck in one Panel that its making me go crazy.
You can see the attach image that represents the objective of this panel and most of it, is done so far.
The objective:
Is for the user to insert Numeric values in "Entry A", then clicks "Button A" so that each one of the items gets added to the right List "ListView B".
The ListView A is dynamic but has, in max, five elements and all of the Entries must be available for fast filling of the user.
The problem:
Im not being able to make the button to add values into that inner ListView because i'm not able to have the ID of it in the code-behind.
Im using Command & CommandParameter in a MVVM structure.
Is the usage of nested ListView possible this way?
Thank you.
If your outer list items type is something like this
public class OuterListItem{
public string EntryAText { get; set; }
public ObservableCollection<string> InnerListItems { get; set; }
}
On your ViewModel you could have something like this
ICommand ButtonCommand = new Command<OuterListItem>((oli) => {
oli.InnerListItems.Add(oli.EntryAText);
oli.EntryAText = String.Empty;
});
and last on your XAML add an x:Name to your page and the button would look like this
<Button Command="{Binding ButtonCommand, Source={x:Reference PageName}}" CommandParameter="{Binding .}"></Button>
You need the x:Name and Source attribute to reference a command which is not implemented within the list item.
This way you do not need any ID.
Related
This will take some explaining.
I'm writing a tool in WPF / C# to dynamically generate, in the view, a visual graph of the data in the view-model. The top-most parent is a grid, and each horizontal row of data is a canvas (inside a border). The canvas holds all the other UI elements (like TextBlocks).
I have a class to hold each row of UI elements in the view.xaml.cs, defined like this:
class ReportRow
{
public Border Divider;
public Canvas Row;
public TextBlock Title;
public List<TextBlock> Phases = new List<TextBlock>();
}
Then I define the entire graph as a List of these Rows:
List<ReportRow> reportRows = new List<ReportRow>();
In the viewmodel.cs, I have the data listed as an ObservableCollection so I can data bind to it and access the data from the view:
public ObservableCollection<SDDeliverable> Deliverables
{
get
{
return this.deliverables;
}
private set
{
this.deliverables = value;
this.RaisePropertyChanged(() => this.Deliverables);
}
}
Back in the view, I loop through the ObservableCollection, creating the rows and assigning the data to the elements (shown without all the styling and positioning, for brevity):
reportRows.Add(new ReportRow());
reportRows[i].Divider = new Border();
ProjectDisplay.Children.Add(reportRows[i].Divider);
reportRows[i].Row = new Canvas();
reportRows[i].Divider.Child = reportRows[i].Row;
reportRows[i].Title = new TextBlock();
reportRows[i].Title.SetBinding(TextBlock.TextProperty, new Binding(string.Format("Deliverables[{0}].DeliverableTitle", i)));
reportRows[i].Row.Children.Add(reportRows[i].Title);
Now, my original problem was that, because I'm binding each individual member of the collection (rather than binding the whole collection to one UI element, like a ListView), the view has no idea how long the collection is, which means I can't use a "foreach" or a loop counter. It worked fine with an arbitrary number of rows, but I didn't want to have to guess.
What I did was add a new label to the UI, bound to the length of the collection, and disguised it as a bit of helpful info:
<Label x:Name="DeliverableCountLabel" Content="{Binding Path=DeliverableCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
this.DeliverableCount = Deliverables.Count;
Once I got that number into a view control, I was able to use it as my loop counter:
int totalItems;
if (int.TryParse(DeliverableCountLabel.Content.ToString(), out totalItems))
{
for (int i = 0; i < totalItems; i += 1)
{
reportRows.Add(new ReportRow());
This is a hacky fix, but I was alright with using it once.
The new problem is that once wasn't enough. As I add more data to the model, I'm hitting the same problem. Each Deliverable has a list of Phases and each Phase has a list of Tasks. I don't want to clutter up the UI with number labels all over the place.
I feel like there should be a way to use a data binding without having it go through the xaml or a visual control element. I just want to bind a variable in the view to a variable in the view-model so I can look at certain bits of info that I don't necessarily want to show the user.
I started messing with doing it this way:
Binding testBinding = new Binding("DeliverableCount");
However, it's the next step that's confounding me. Everything I've tried past that point has been incorrect somehow.
// returns the binding object itself, not the bound value
testBinding.ToString();
// error (not a real thing you can do, apparently)
string testString;
testString.SetBinding (testBinding);
How do I send a value from view-model to view without having to display it on-screen somewhere? Am I going about this the wrong way? Is this even possible?
A last-ditch idea I have is to create one dummy label and either make it invisible somehow or hide it behind another element. Then I could write a function to update the data binding on this one specific label any time I needed to access something in the view-model that's not shown on-screen. However, this really feels like a hack of a hack and I'd rather not go down that road unless it's really the best (or only) option.
This is how I ended up solving this. It's hacky, but it works.
I created a label in the xaml and set it's visibility to hidden. Then I just call one of these functions:
public string TempStringBind(string bind)
{
DummyLabel.SetBinding(Label.ContentProperty, new Binding(bind));
return DummyLabel.Content.ToString();
}
public int TempIntBind(string bind)
{
DummyLabel.SetBinding(Label.ContentProperty, new Binding(bind));
int newInt;
if (DummyLabel.Content != null && int.TryParse(DummyLabel.Content.ToString(), out newInt))
{
return newInt;
}
else
{
return -1;
}
}
This will take any variable from the view-model that can be bound to, bind it to an invisible label, grab that value from the label, and return it to me in the view in a useable form. While it's still going through something in the view xaml, the benefit is that the user doesn't have to see a bunch of extra controls or data they don't care about just to find out how many rows or columns I need to make for lists.
The ItemsSource method would be a lot cleaner, but that only works if I'm sticking the data in an existing control, like a ListView or a ComboBox, which aren't good for making visual charts and graphs with exact positioning.
I'm not sure what you guys meant by it not being MVVM. I've got the M, the V, and the VM all in there. :P
I've got a Windows 8 Store form with multiple controls, a.o. lots of comboboxes, 2 I show below. I can populate them using databinding to a number of ObservableCollections (most used in multiple comboboxes, like prMachType). This works to databind the content to display.
<ComboBox x:Name="machinetype" ItemsSource="{Binding prMachtype}" SelectedItem="{Binding SelectedClass, Mode=TwoWay}" />
However I am not sure how to get the results of the controls the user enters into another ObservableCollection. The 'set' below is called (only when I add Mode=TwoWay in the XAML) when I change a value in the combobox machinetype:
public SchwDescr SelectedClass
{
get
{
return _SelectedClass;
}
set
{
if (_SelectedClass != value)
{
_SelectedClass = value;
RaisePropertyChanged("SelectedClass");
}
}
}
_SelectedClass contains the properties of the assigned ObservableCollection (like Description and Key) but now I would need to have this key (e.g. "00005") and field used (machinetype, as in the name of the combobox) together to store in another ObservableCollection (containing Field + Key, so machinetype and "00005" when this combobox is selected. I do not see which control (here combobox machinetype) the user is changing here so I can't store the field+selection 'manually' and I also don't see how I can databind directly to such an ObservableCollection so key+field are update directly and also show the (stored) selection when I load the data again (the preferred way of course).
Can someone lead me to the right direction (like a full sample)?
I'm new to Windows Phone 7 development. I need to create a page very similar to the settings app page. Something like this (but without the menu at the top and the subtext for each item):
(source: dotnetapp.com)
So far I've got a listbox with items, but clicking on one of the items, the item color changes and it doesn't have the "pushed button" effect like the settings application has.
First question is how do I create this beautiful pushed button effect (notice that the button tilts when pressed depending on the position of the click).
My second question is about styling items differently. The ItemsSource of the listBox is defined like this:
List<string> firstList;
List<string> secondList;
public MainPage()
{
...
List<string> lst = new List<string>();
lst.AddRange(firstList);
lst.AddRange(secondList);
listBox1.ItemsSource = lst;
...
I need to style the items differently whether they come from firstList or secondList, for example if the item is from firstList its color should be blue.
I think it should be done using StaticResource, but i'm not sure. Maybe I'll need to somehow wrap the string so that it will have a getter for defining from which list it comes from.
Thanks.
Question 1 is answered (see William Mekanis comment)
For question 2 you have one big problem... you are binding a list of strings... no change to see which item is coming from which list.
I would create something like a view model for my DataSource list.
Something like (NotifyPropertyChanged is ignored here, implement it if needed and use an ObservableCollection also ;) ):
public class ListDataSourceViewModel
{
public string Text {get; set;}
public bool IsFromFirstList {get; set;}
}
In case you have more lists you could also use an enum or whatever as list identifier...
That you create a new list for the DataSource like:
lst.AddRange(firstList.Select(item => new ListDataSourceViewModel
{
Text = item, IsFromFirstList = true
}
).ToArray());
lst.AddRange(secondList.Select(item => new ListDataSourceViewModel
{
Text = item, IsFromFirstList = false
}
).ToArray());
Afterwards create a datatemplate for your listitem binding the text to a textblock and the font color for your textblock to the IsFromFirstList property using a converter.
This code is written from mind, without VS... not shure if u can copy paste without problem but it should give you the idea ;)
If you need help with creating the datatemplate and the converter just tell me!
Edit:
I rethought my suggestion... using converters, specialy in (potential) large lists, is not a good idea (for performance point of view). In your case it is anyway not a problem to use the needed color directly in the viewmodel.
I would change
public bool IsFromFirstList {get; set;}
to
public Color WhatEverColor {get; set;}
set it as needed when the VMs are created and bind it to wherever you need it.
Hope it helps!
I am using a mvvm pattern for an application that sources its data from a sql ce database using the Entity Framework version 4. The WPF application only has one view (don't need anymore as the app is not that big). I am displaying a collection of properties from the database in a listbox, by creating an observablecollection in my viewmodel and binding this. This works exactly as expected. The issue is that I now have another listbox (in the same view) that needs to be populated with Images for each property. To be clear, each property has a bunch of images, but each image is only assigned to one property.
What would be the best way to display the images, I thought maybe creating another observablecollection for the images, but I am not sure how I would then ensure that only images for the appropriate property are shown. Or should I simply bind the listbox to the Images property of each property (house)?
Cheers
private void Load()
{
PropertyList = new ObservableCollection<Property>((from property in entities.Properties.Include("Images")
select property));
propertyView = CollectionViewSource.GetDefaultView(PropertyList);
if (propertyView != null)
propertyView.CurrentChanged += new System.EventHandler(propertyView_CurrentChanged);
RaisePropertyChanged("CurrentContact");
RaisePropertyChanged("SaleTitle");
RaisePropertyChanged("Address");
RaisePropertyChanged("AuctioneerName");
RaisePropertyChanged("AgentName");
RaisePropertyChanged("Price");
RaisePropertyChanged("NextBid");
RaisePropertyChanged("Status");
}
That sounds distinctly like a different responsibility (a master/details view). In the true spirit of MVVM I'd create a new View and a new ViewModel - perhaps:
PropertyImagesViewModel
- public Property Property { get; set; }
- public IList<Image> Images { get; set; }
- public int SelectedIndex { get; set; }
PropertyImagesView
Don't forgot to call RaisePropertyChanged() in each of the property setters
Also note that ObservableCollection does nothing if you aren't manipulating the contents one-at-a-time. If all do you is update the entire collection all-at-once, then it gives you no tangible benefit.
Another thing - if you need to notify that all your properties changed:
RaisePropertyChanged(null);
will do the trick.
I have a MVVM application with a MainWindowViewModel connected to a MainWindowview.
On the MainWindow view I have a ComboBox containing stock ticker symbols.
I have another viewmodel and view called AllStockQuoteViewModel connected to AllStockQuoteView which contains a list of stocks and their prices.
I want to be able to select an item from the ComboBox and have the item in the AllStockQuoteView selected and highlighted. On my MainWindowViewModel I have saved the reference to the AllStockQuoteViewModel and use it to call a method to find the stock ticker symbol in the ObservableCollection bound to the AllStockQuoteView, but haven't found a way to programmatically select the item on the AllStockQuoteView.
I have a SelectedQuote property on the AllStockQuoteViewModel bound to the listview on the AllStockQuoteView and I can select one of the items and my SelectedQuote property is set fine. If I set this programmatically in my SelectQuote method, it doesn't appear as if the item is selected in the view, although the item is passed back to the MainWindowViewModel and I can use it to populate the textblocks on MainWindow view.
I'd like to be able to show the item on the AllStockQuoteView as being selected via highlighting as if the user selected it.
How can this be done?
Its very easy to implement
You need two things in your view model
A List of your objects and a selected item property
private CustomObject _selectedCustomObject;
public ObservableCollection<CustomObject> CustomObjects
{
get
{
return new ObservableCollection<CustomObject>();
}
}
public CustomObject SelectedCustomObject
{
get { return _selectedCustomObject; }
set
{
if (_selectedCustomObject== value)
{
return;
}
_selectedCustomObject= value;
PropertyChanged.Raise(this, x => x.SelectedCustomObject);
}
}
Then in your view you add your List/Combo control and bind to both properties.
<ListView ItemsSource="{Binding CustomObjects}"
SelectedItem="{Binding SelectedCustomObject}">
Then all you need to do is set the viewmodel properties and the view will update.
First you have to think about your model and the whole MVVM approach, a good starting point is http://blogs.msdn.com/b/kashiffl/archive/2010/11/14/mvvm-technical-description.aspx.
After you can implement your functionality by different ways, one would be to implement something like the Observer Pattern or you try to use methods like Notify Property-Changed-Events.
Hope i was able to help,
Greetings