In the below code:
RectifiedString is property of a class say 'X'.
i.e List<StringDetails> RectifiedString { get; set; }.
StringDetails has fields: InitialString, FinalString, isSelected. I want to have a checklistListBox with the list of rectified strings. However, the content of the CheckBox is a string which is a combination of InitialString & FinalString.I am trying to get something like the first box, but I am getting the second box.
<ListBox Grid.Row="6"
ScrollViewer.VerticalScrollBarVisibility="Auto" ItemsSource="{Binding RectifiedString}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox>
<CheckBox.Content>
<StackPanel>
<Label Content="Initial String"/>
<TextBlock Text="{Binding InitialString}"/>
<Label Content="Final String"/>
<TextBlock Text="{Binding FinalString}"/>
</StackPanel>
</CheckBox.Content>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
Note :
I have taken care of the scope of Class X.
When I replace the Binding on textblocks with static strings, they work fine except that it has additional padding around the textblock.
In the image, there is a small correction. I am not shown the Initial String in any of the three items in the list. I am shown the correct final string though. Basically, it is only binding one textblock only - the final string in this case.
Another problem that I was facing: I am unable to bind the isChecked Property of the CheckBox with the isSelected property of RectifiedString. It is showing me errors if I add isChecked="{Binding isSelected}" inside the <CheckBox>
Tried this and it works on my pc. If i'm not wrong you said you had a class like:
public class StringDetails
{
public string InitialString
{ get; set; }
public string FinalString
{ get; set; }
}
And let's say you have your list initialized like
RectifiedString = new List<StringDetails>() {new StringDetails { InitialString = "AAA", FinalString= "BBB" }, new StringDetails { InitialString = "BBB", FinalString = "AAA" } };
You should check your "stringDetails" names because it works.
You could post your codebehind/MVVM code so we can take a look there.
Related
I'm using Xamarin.Forms (C#) and am attempting an MVVM approach.
My classes:
public class Parent
{
public string FirstName { get; set; }
public Child Children { get; set; }
public Parent GetOneParent() {...}
}
public class Child
{
public string FavoriteFruit { get; set; }
}
First of all, what is this type of class called having a "compound" property (i.e. a collection of children)? I don't know what this is referred to so I am limited in "Googling" it.
Ok, I create a single Parent object:
Parent OneParent = new Parent.GetOneParent();
Now I'd like to show in my XAML code:
parent name (in a label)
a list of children's favorite fruits (in a listview since there are multiple)
What's the binding syntax for a label and then a listview for this type of object? {Binding ???}
The answer turned out to be rather simple... the binding context has to be specific to the page and then also more deeply, its controls.
So I did something like this...
In code-behind, I set the binding context:
BindingContext = Parent;
Then in the XAML code...
<StackLayout>
<Label Text="{Binding FirstName}" />
</StackLayout>
<StackLayout>
<!-- Now specify a deeper within the Parent object -->
<ListView x:Name="ParticipantList"
ItemsSource="{Binding Participants}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding FavoriteFruit}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Hope that helps someone down the road!
Given a list of objects containing two properties (IdentityType and Name) in the format:
IdentityType | Name
A | One
A | Two
A | Three
B | Four
B | Five
C | Six
Is there a way to declaratively databind that so the accordion displays like this?
A
- One
- Two
- Three
B
- Four
- Five
C
- Six
So far the best I can get is a panel header for each item, like so:
<toolkit:Accordion ItemsSource="{Binding Path=Identities}" Grid.Row="2" SelectionMode="ZeroOrMore">
<toolkit:Accordion.ItemTemplate>
<DataTemplate >
<TextBlock Text="{Binding IdentityType, Converter={StaticResource EnumDescriptionConverter}}"/>
</DataTemplate>
</toolkit:Accordion.ItemTemplate>
<toolkit:Accordion.ContentTemplate>
<DataTemplate>
<StackPanel Margin="5" Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Foreground="White" />
</StackPanel>
</DataTemplate>
</toolkit:Accordion.ContentTemplate>
</toolkit:Accordion>
I'm new to Silverlight so I could be missing something blindingly obvious, but any help would be very much appreciated!
You can do this with a view model inbetween your model (the initail list) and your view (the markup).
Create a view model class with a Title and a NameCollection
Use LINQ (or a simple foreach) to translate your existing list of 6 entities to a list of 3 entites with 3, 2 and 1 Names in their name collection respectively.
Bind your Accordions ItemsSource to the collection of ViewModel objects.
Bind the text block in the your accordion items header template to your Title property
Add a repeating item control like ItemsControl to your content template of your accordion item
Bind your repeating item to the NamesCollection
Assuming your model is as follows...
public class Model
{
public string Title { get; set; }
public string Name { get; set; }
}
Your View Model structure should be...
public class ViewModel
{
public string Title { get; set; }
public List<string> Names { get; set; }
}
public class DataContextClass
{
public DataContextClass()
{
var modelData = new ModelData();
var query = from m in modelData.ModelCollection
group m by m.Title
into vm select new ViewModel { Title = vm.Key, Names = vm.Select(x => x.Name).ToList() };
ViewModelCollection = query.ToList();
}
public List<ViewModel> ViewModelCollection { get; set; }
}
Then your view can create an instance of your DataContextClass, assign it to it's own DataContext property and then use this markup...
<layout:Accordion ItemsSource="{Binding Path=ViewModelDataInstance.ViewModelCollection}" >
<layout:Accordion.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</layout:Accordion.ItemTemplate>
<layout:Accordion.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Names}" />
</DataTemplate>
</layout:Accordion.ContentTemplate>
</layout:Accordion>
You can also use Tuple instead.
Code becomes :
public class DataContextClass{
public DataContextClass()
{
var modelData = new ModelData();
var query = from m in modelData.ModelCollection
group m by m.Title
into vm select Tuple.Create(vm.Key, vm.Select(x => x.Name).ToList() };
Collection = query.ToList();
}
public Tuple<string,List<string>> Collection { get; set; }
}
Xaml become :
<layout:Accordion ItemsSource="{Binding Path=ViewModelDataInstance.ViewModelCollection}" >
<layout:Accordion.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Item1}" />
</DataTemplate>
</layout:Accordion.ItemTemplate>
<layout:Accordion.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Item2}" />
</DataTemplate>
</layout:Accordion.ContentTemplate>
I hope it helps
I am databinding a view to a viewmodel and am having trouble initializing a combobox to a default value. A simplification of the class I'm using in the binding is
public class LanguageDetails
{
public string Code { get; set; }
public string Name { get; set; }
public string EnglishName { get; set; }
public string DisplayName
{
get
{
if (this.Name == this.EnglishName)
{
return this.Name;
}
return String.Format("{0} ({1})", this.Name, this.EnglishName);
}
}
}
The combobox is declared in the view's XAML as
<ComboBox x:Name="LanguageSelector" Grid.Row="0" Grid.Column="1"
SelectedItem="{Binding SelectedLanguage,Mode=TwoWay}"
ItemsSource="{Binding AvailableLanguages}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
and the viewmodel contains this code
private List<LanguageDetails> _availableLanguages;
private LanguageDetails _selectedLanguage;
public LoginViewModel()
{
_availableLanguages = LanguageManager.GetLanguageDetailsForSet(BaseApp.AppLanguageSetID);
_selectedLanguage = _availableLanguages.SingleOrDefault(l => l.Code == "en");
}
public LanguageDetails SelectedLanguage
{
get { return _selectedLanguage; }
set
{
_selectedLanguage = value;
OnPropertyChanged("SelectedLanguage");
}
}
public List<LanguageDetails> AvailableLanguages
{
get { return _availableLanguages; }
set
{
_availableLanguages = value;
OnPropertyChanged("AvailableLanguages");
}
}
At the end of the constructor both _availableLanguages and _selectedLanguage variables are set as expected, the combobox's pulldown list contains all items in _availableLanguages but the selected value is not displayed in the combobox. Selecting an item from the pulldown correctly displays it and sets the SelectedLanguage property in the viewmodel. A breakpoint in the setter reveals that _selectedLanguage still contains what it was initialized to until it is overwritten with value.
I suspect that there is some little thing I'm missing, but after trying various things and much googling I'm still stumped. I could achieve the desired result in other ways but really want to get a handle on the proper use of databinding.
You need to change the order of you bindings in XAML so that your ItemsSource binds before the SelectedItem.
<ComboBox x:Name="LanguageSelector" Width="100"
ItemsSource="{Binding AvailableLanguages}"
SelectedItem="{Binding SelectedLanguage,Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
If you set a breakpoint on the 'get' of both the SeletedLanguage and AvailibleLanguage, you will notice that the SelectedLanguage gets hit before your AvailibleLanguage. Since that's happening, it's unable to set the SelectedLanguage because the ItemsSource is not yet populated. Changing the order of the bindings in your XAML will make the AvailibleLanguages get hit first, then the SelectedLanguage. This should solve your problem.
1) When you assign the SelectedLanguage, use the public property SelectedLanguage instead of the private _selectedLanguage, so that the setter gets executed,
2) You need to move the assignment of the selectedlanguage to the moment that the view has been loaded. You can do it by implementing the Loaded event handler on the View. If you want to be "mvvm compliant" then you should use a Blend behavior that will map UI loaded event to a viewmodel command implementation in which you would set the selected language.
I have an ItemsControl with a DataTemplate that has been defined. My ItemsControl definition looks like the following:
<ItemsControl x:Name="myItemsControl" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<CheckBox x:Name="myCheckBox" Content="{Binding Name}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is a simplified version of my DataTemplate. Regardless, when a user clicks a button on the page, I want to loop through the items in myItemsControl and determine if the CheckBox element associated with the item is checked.
How do I determine if a CheckBox is checked for a specific item within an ItemsControl?
Thank you!
Add a property to your data class and databind it, then iterate over the collection itself.
public class myDataClass
{
public string Name { get; set;}
public bool IsSomething { get; set; }
}
<CheckBox x:Name="myCheckBox" Content="{Binding Name}" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
You can try something like traditional iteration:
public bool? TestMyCheckbox(string bindingName)
{
foreach (var item in myItemsControl.Items)
{
if (item.GetType() == typeof(CheckBox))
{
var checkbox = (CheckBox)item;
if (checkbox.Content.Equals(bindingName))
{
return (checkbox.IsChecked);
}
}
}
return null;
}
Additionaly (this may better fit your needs) you can look for a list of checkboxes bindings that are checked:
public IEnumerable<object> TestMyCheckboxes(ItemsControl control)
{
return from Control x in control.Items
where x.GetType().Equals(typeof(CheckBox)) && ((CheckBox)x).IsChecked == true
select ((CheckBox)x).Content;
}
(How long have we been using OpenIDs? I don't seem to have one connected to any provider and no FAQ on the planet seems to tell you what to do when you lose your OpenID. I've had to create a new account. Argh!)
I'm trying to fill a (carousel) listbox from a database, but I can't get the images to display. Every single example on the net assumes you have two or three jpegs in a folder instead of in memory :(
My item class is:
public class PicCollection : ObservableCollection<CarouselItem>
{
public PicCollection()
{
}
}
public class CarouselItem
{
public int ItemID { get; set; }
public string ItemName { get; set; }
public string ItemDesc { get; set; }
public Image ItemImage { get; set; }
public CarouselItem(int NewItemID, string NewItemName, string NewItemDesc, Image newItemImage)
{
this.ItemID = NewItemID;
this.ItemName = NewItemName;
this.ItemDesc = NewItemDesc;
this.ItemImage = newItemImage;
}
}
I fill a PicCollection successfully from the db(using a byte array for the image), and try to display the name and image with
<DataTemplate x:Key="TestDataTemplate2" >
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="CarName"
Text="{Binding ItemName}"
Padding="15,15"
Foreground="Yellow" />
<Image Source="{Binding Source=ItemImage}"
Stretch="Fill" />
</StackPanel>
</DataTemplate>
Listbox is simply:
<ListBox Name="lstTest" ItemsSource="{StaticResource TestDataSource}"
ItemTemplate="{StaticResource TestDataTemplate2}"></ListBox>
ItemName displays ok, ItemImage does not. I've tried {Binding ItemImage} as well. Most examples use {Binding Path=ItemImage} but that's where the ItemImage would be a string containing the path, not the actual image itself.
I'm pulling my hair out. Nothing I do makes the images appear. If I create an image control and manually assign the contents of an ItemImage, however, it displays fine. What am I doing wrong?
Your ItemImage property is an Image (control). Make it an ImageSource, such as a System.Windows.Media.Imaging.BitmapImage. Then you can bind <Image Source="{Binding ItemImage}" />.
Since your "ItemImage" property is already an image, you might be able to get away with just using a ContentControl to display the image directly:
<ContentControl Content="{Binding Image}" />