Add static item to RadComboBox in WPF - c#

I have a set of two cascading RadComboBoxes - when one is set, the other populates. The second combobox has its ItemSource set to a CompositeCollection that's binding to an ObservableCollection in the viewmodel.
I'm attempting to add a static value to the list. The idea is that the CompositeCollection can change, but there should always be one static ComboBoxItem available named Other.
CustomerContact.cs:
public class CustomerContact
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
CustomerContactSource:
<CollectionViewSource x:Key="CustomerContactSource" Source="{Binding CustomerSite.CustomerContacts}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
OtherCustomerContact:
public CustomerContact OtherCustomerContactItem => new CustomerContact
{
Name = "Other",
Email = string.Empty,
PhoneNumber = string.Empty
};
Xaml page:
<telerik:RadComboBox ItemTemplate="{StaticResource ComboBoxItemTemplate}"
SelectedItem="{Binding CustomerContact}"
Text="{Binding Source=CustomerContact, Path=Name}">
<telerik:RadComboBox.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource CustomerContactSource}}"/>
<TextBlock Text="{Binding Source=OtherCustomerContactItem, Path=Name}"/>
</CompositeCollection>
</telerik:RadComboBox.ItemsSource>
</telerik:RadComboBox>
I keep getting an error stating that no converter can be found for TextBlock to CustomerContact. What am I doing wrong? The RadComboBox has an ItemSource that's a list of CustomerContact and a single, unchanging item that's also of type CustomerContact.
Any help would be greatly appreciated!!!

The RadComboBox has an ItemSource that's a list of CustomerContact and
a single, unchanging item that's also of type CustomerContact.
That last part doesn't hold. You're wrapping the item in a TextBlock and that's
the type XAML sees. Giving an error due to lack of TypeConverter.
You could wrap the item:
in a Collection(Container) of its own.
in a RadComboBoxItem in the lines of what is
done here for a ListBox.

Related

ListView item not displayed correctly

I have an ObservableCollection as the ItemsSource for a ListView.
Adding items works fine and the ListView updates, but in the ListView all I can see is this:
What am i missing?
public class MenuItem
{
public string Item { get; set; }
public string Price { get; set; }
}
// ...
public ObservableCollection<MenuItem> MenuItemList = new ObservableCollection<MenuItem>();
// ...
MenuItemList.Add(new MenuItem {Item = MenuData[6].InnerText, Price = PriceData[6].InnerText});
// ...
listViewFood.ItemsSource = MenuItemList;
You created a custom type MenuItem. The ListView has no way of knowing how to display items of this type, that is why it displays the result of ToString, which is the type name here. You have to define the appearance of an item yourself using a DataTemplate as ItemTemplate, e.g.:
<ListView x:Name="listViewFood">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type MenuItem}">
<StackPanel>
<TextBlock Text="{Binding Item}"/>
<TextBlock Text="{Binding Price}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For more information see the Data Templating Overview, which covers the mechanics in detail.

Object Binding in Caliburn.Micro MVVM Framework with SelectedItem

I have the following Models:
public class Profile
{
public string name { get; set; }
public Member casemanager { get; set; }
public Member assistant { get; set; }
}
public class Member
{
public int Id { get; set; }
public int Type{ get; set; }
public string Name { get; set; }
}
In my ViewModel, I have the following objects:
an ObservableCollection<Profile> named Profiles that gets populated from a database;
a SelectedProfile of type Profile, of course;
Two Lists of Members named ListCaseManagers and ListAssistants that get populated from DB.
Each of the objects implement a NotifyOfPropertyChange method from Caliburn.Micro and are set with property and backing field.
The View:
<StackPanel>
<ListView ItemsSource="{Binding Profiles}" SelectedItem="{Binding SelectedProfile}" DisplayMemberPath="name" SelectionMode="Single" />
<ComboBox ItemsSource="{Binding ListCaseManagers}" SelectedItem="{Binding SelectedProfile.casemanager }" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="Name"/>
<ComboBox ItemsSource="{Binding ListAssistants}" SelectedItem="{Binding SelectedProfile.assistant}" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="Name"/>
</StackPanel>
In this XAML I was thinking that the SelectedItem of each ComboBox would bind directly to the SelectedProfile casemanager/assistant, changing everytime I modify the SelectedProfile using the ListView, but it doesn't seem to select the item in the combobox even though SelectedProfile.casemanager and SelectedProfile.assistant are not null.
What am I missing? Is there an easy way using conventions with Caliburn.Micro?
In combobox present couple properties which can allow you to modify your SelectedItem in your list.
SelectedValuePath="Id" <br/>
SelectedValue="{Binding SelectedProfile.casemanager.Id}"
Upd: this approach allow to bind selected element by their some unique attribute (ID or Name)
In case if you need to work with SelectedItem.. you must sure that props of items in Profiles collection are related to object in ListCaseManagers and ListAssistants
var query = from p in Profiles
join mgr in ListCaseManagers on p.casemanager==mgr
select p;
? query.Count
enter code here
I assume you will see 0.. since objects in collection are different.
to use the convention name of Caliburn, you have to give a name to your control
for example for ListView:
<StackPanel>
<ListView x:Name ="Profiles" />
</StackPanel>
with the convention of names, Caliburn binds automatically the collection Profiles and use SelectedProfiles as SelectedItem
You either need to raise the PropertyChanged for the SelectedProfile property when it's set:
private Profile_selectedProfile;
public ProfileSelectedProfile
{
get { return _selectedProfile; }
set
{
_selectedProfile = value;
NotifyOfPropertyChange(() => SelectedProfile);
}
}
Or you could bind to the SelectedItem property of the ListView control itself:
<StackPanel>
<ListView x:Name="lv" ItemsSource="{Binding Profiles}"
SelectedItem="{Binding SelectedProfile}"
DisplayMemberPath="name" SelectionMode="Single" />
<ComboBox ItemsSource="{Binding ListCaseManagers}"
SelectedItem="{Binding SelectedItem.casemanager, ElementName=lv }"
DisplayMemberPath="Name"/>
<ComboBox ItemsSource="{Binding ListAssistants}"
SelectedItem="{Binding SelectedItem.assistant, ElementName=lv}"
DisplayMemberPath="Name"/>
</StackPanel>

How to Populate an ObservableCollection through bindings

Hello I'm trying to Populate an Observable Collection through selected items of an Autocompletebox.
<Telerik:RadAutoCompleteBox Itemssource="{Binding People}" />
How should I initiate the Observable Collection to bind with RadAutocompleteBox.
And how should I set up SelectedItems binding method.
public class People
{
public string Person
{ get; set; }
public DateTime Date
{ get; set; }
}
public ObservableCollection<string> Persons{ get; set; }
You could try this to get the SelectedItems :
Add this to your viewmodel and edit your XAML.
ViewModel:
public ObservableCollection<People> SelectedPeoples { get; set; }
Xaml:
<Telerik:RadAutoCompleteBox Itemssource="{Binding People}"
SelectedItems="{Binding SelectedPeoples , Mode=TwoWay}"
SelectionMode="Multiple" />
After your edit
I see that you try to bind a class to the RadAutoCompleteBox rather than the ObservableCollection People, you have to bind the property Persons to the RadAutocompleteBox. This will bind the ObservableCollection to the RadAutoCompleteBox.
<Telerik:RadAutoCompleteBox Itemssource="{Binding Persons}" />
Also, you can edit the declaration of your ObservableCollection to
public ObservableCollection<People> Persons{ get; set; }
and edit the XAML like this:
<Telerik:RadAutoCompleteBox Itemssource="{Binding Persons}" DataMemberPath="Person" />
Your RadAutocompleteBox will now show the string Person declared in your People class.
If I'm looking at your code right, you are binding the items source to the class rather than to the collection. For an item's source binding to the collection is needed. You set the data context to the class.
Itemssource="{Binding Persons}"

WPF Data Binding an ObservableCollection (or LinkedList) to a WrapPanel

Ok. First of all, I've looked at a bunch of other questions and a ton of other places on the internet on how to do this, and none of them are helping, so please don't mark this as a duplicate, and also, heads up cause I probably made a really stupid mistake.
I'm trying to bind an ObservableCollection to a WrapPanel using an ItemsControl and a DataTemplate. The following is my XAML Code:
<ItemsControl x:Name="wPanel">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--<Border BorderBrush="DarkGray" Background="Transparent">-->
<StackPanel MinWidth="250">
<Grid>
<TextBlock Text="{Binding address}" />
</Grid>
<Grid>
</Grid>
</StackPanel>
<!--</Border>-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note: I did have (for the ItemsSource property of ItemsControl) {Binding properties}
This is my declaration of properties:
public ObservableCollection<Property> properties = new ObservableCollection<Property>();
And the Property Class is the following plus many more properties:
private string address { get; set; }
private string city { get; set; }
private string postcode { get; set; }
private double price { get; set; }
private LinkedList<Tennant> tennants { get; set; }
...
I thought I had solved the problem with this,
Binding binding = new Binding();
binding.Source = properties;
wPanel.SetBinding(ItemsControl.ItemsSourceProperty, binding);
But, then the line in the xaml: <TextBlock Text="{Binding address}" /> didn't work.
Then I came to the conclusion that it had to do with the properties object, and how it wouldn't bind unless I did it through code.
What am I doing wrong, for it not bind through XAML, etc.? What do I need to change about the properties object, or what do I need to do?
Thanks in advance.
You can bind ItemsControl's ItemsSource to properties just like #AjS answer. But before that, you need to change properties declaration to be property instead of field.
public ObservableCollection<Property> properties { get; set; }
And also address property of your Property class need to be public.
public string address { get; set; }
Isn't the 'properties' a property on the window?
If you are binding in xaml, make sure you use declare 'properties' as 'Property', set datacontext of window to itself and then set binding path:-
<ItemsControl x:Name="wPanel" ItemsSource="{Binding properties}">
this.DataContext=this; //set datacontext on parent window or control
If you are doing it in code, setting the ItemsSource directly on wPanel should work:-
wPanel.ItemsSource=properties;
This is easy trick for check Binding. Every WPF developer must know this. For example:
<TextBlock Text="{Binding}" />
Run and see it.
If TextBlock has any object in DataContext, object class name displayed in TextBlock.
If DataContext has empty. TextBlock is Empty

WPF Binding Combox with different List and different SelectedValue

In my UserControl ucStep2 I have DataContext of Step2InfoData object that has several properties along with :
private string rockDensUnit;
public string RockDensity_Unit
{
get { return rockDensUnit; }
set
{
if (rockDensUnit != value)
{
rockDensUnit = value;
Changed("RockDensity_Unit");
}
}
}
In my app I got to bind several combo's with different normally measurement types Like {kg/m3, gm/m3}, {meter, cm} and so on such groups of measures. I mean, multiple combo's to have list of same items. So I preferred to create Class's of such lists that I can use in multiple combos. I created ComboItems.cs which contains all items lists that I will need to populate the drop down.
ComboItems.cs
//**OBJECTS I USE FOR LIST OF IEMS**
// Class for kg, gm
public class KgGmItems
{
public ObservableCollection<string> KgGmList { get; set; }
public KgGmItems()
{
KgGmList = new ObservableCollection<string>();
KgGmList.Add("kg/m3");
KgGmList.Add("gram/cm3");
}
public string ValueSelected { get; set; } // Don't know if this is useful in my case
}
// Class for meter, cm
public class MtCmItems : INotifyPropertyChanged
{
public MtCmItems()
{
Dict = new Dictionary<string, string>
{
{"meter", "meter"},
{"centimeter", "centimeter"}
};
}
//...
}
XML i.e. ucStep2 View
<!-- As the objects KgGmItems doesn't contain in ucStep2.xaml.cs or Step2InfoData (that is bound to this UC) so add reference of those classes -->
<UserControl.Resources>
<ObjectDataProvider x:Key="KgGmObj" ObjectType="{x:Type top:KgGmItems}" />
<ObjectDataProvider x:Key="MtCmObj" ObjectType="{x:Type top:MtCmItems}" />
</UserControl.Resources>
<ComboBox DataContext="{StaticResource KgGmObj}" ItemsSource="{Binding KgGmList}" SelectedValue="{Binding Path=RockDensity_Unit, Mode=TwoWay}" SelectedIndex="0"
Background="#FFB7B39D" Grid.Row="5" Height="23" HorizontalAlignment="Left" Margin="401,61,0,0" Name="comboBox6" VerticalAlignment="Top" Width="84" Visibility="Hidden">
</ComboBox>
I want to display ObservableCllection KgGmList items from KgGmItems class and bind the selected value to RockDensity_Unit of class Step2InfoData that is bound to this UserControl.
In the above combo, I am able to display all items in the drop down, also 1st item is selected by default. But the value is not bind to RockDensity_Unit; it's value remains null.
I want this to happen 2-way i.e. when RockDensity_Unit proeprtiy's value is set programmatically, the value should be selected in the drop down. Of course the value should exists in the list.
By default the 1st item should be selected.
UPDATE
Added DependencyProperty in ucStep2.xaml.cs
public static readonly DependencyProperty RockDensityUnitProperty =
DependencyProperty.Register("RockDensity_Unit", typeof(string), typeof(UserControl),
new FrameworkPropertyMetadata("kg/m3", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string RockDensity_Unit
{
get { return this.GetValue(RockDensityUnitProperty) as string; }
set { SetValue(RockDensityUnitProperty, value); }
}
XML
<ComboBox DataContext="{StaticResource KgGmObj}" ItemsSource="{Binding KgGmList}" SelectedItem="{Binding Path=RockDensity_Unit, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ucStep2}}, Mode=TwoWay}"
Background="#FFB7B39D" Grid.Row="5" Height="23" HorizontalAlignment="Left" Margin="401,61,0,0" Name="comboBox6" VerticalAlignment="Top" Width="84" Visibility="Hidden">
</ComboBox>
ERROR
Error 1 The type reference cannot find a public type named 'ucStep2'. Line 74 Position 194. This refers to the combobox ", "
after FindAncestor
DOUBT
The RockDensity_Unit CLR property in Step2InfoData is untouched.
Why is the code not able to find ucStep2 ? FYI, I think this may be relevant :
<UserControl x:Class="WellBore.ucStep2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WellBore.Models"
xmlns:top="clr-namespace:WellBore"
mc:Ignorable="d"
d:DesignHeight="870" d:DesignWidth="700" MaxHeight="970" MinHeight="700" MaxWidth="600">
Ok, so let's get this binding working... first, I am using an item from your KgGmItems class to bind to the ComboBox. In this class you have a collection of string values to display in the drop down and a string property to bind to the ComboBox.SelectedItem... perfect! Now I'm assuming that you have an instance of this class in the Resources section called KgGmObj... let's keep it simple to start with:
<ComboBox DataContext="{StaticResource KgGmObj}" ItemsSource="{Binding KgGmList}"
SelectedItem="{Binding ValueSelected, Mode=TwoWay}" />
This is all you need to setup the binding between the ComboBox and your class. One thing to note though, is that when you try to set the selected item from your code, it will only work if you set it to one of the actual items in the collection... I think that this doesn't really count when using strings, but it's important to know this anyway. If you were setting a custom class as the type of objects in the ComboBox instead, then you could set the selected item like this:
ValueSelected = KgGmList.Where(item => item.Name == "NameOfObjectToMatch").Single();
Or better like this if you had a uniquely identifiable property:
ValueSelected = KgGmList.Where(item => item.Id == Id).Single()
With your string values, you should be able to set the selected item from code like this:
ValueSelected = "Some value";
UPDATE >>> Ok, so let's have another go... I think that I may have enough information to go on now. I think that you want something like this:
<ComboBox DataContext="{StaticResource KgGmObj}" ItemsSource="{Binding KgGmList}"
SelectedItem="{Binding RockDensity_Unit, Mode=TwoWay}" />
The problem with this is that you have set the DataContext of the ComboBox to your KgGmObj object. This means that the Framework is going to try to find a property named RockDensity_Unit in that object. I also see another potential problem in your definition of this property.
In order to bind from a UserControl xaml to its code behind, you need to use a DependencyProperty. You can find out how to implement these from the Dependency Properties Overview page at MSDN. So first, I would recommend that you implement your RockDensity_Unit property as a DependencyProperty.
Next, we have to find a way to that property from the ComboBox in the xaml... we can do that using a RelativeSource binding like this:
<ComboBox DataContext="{StaticResource KgGmObj}" ItemsSource="{Binding KgGmList}"
SelectedItem="{Binding RockDensity_Unit, RelativeSource={RelativeSource Mode=
FindAncestor, AncestorType={x:Type ucStep2}}, Mode=TwoWay}" />
Now, if you have a DependencyProperty to bind to the SelectedItem property and your UserControl class is named ucStep2, this should all work... let me know how it goes.
UPDATE 2 >>>
Your error is because you have to add an XML namespace at the top of your XAML file... something like this:
xmlns:YourNamespace="clr-namespace:ApplicationName.FolderNameContainingClass"
Then you use it to reference your class like this:
...AncestorType={x:Type YourNamespace:ucStep2} ...
Also, in your DependencyProperty declaration, you're supposed to supply the name the type of your control, not UserControl, so change
Register("RockDensity_Unit", typeof(string), typeof(UserControl),
to
Register("RockDensity_Unit", typeof(string), typeof(NameOfYourUserControl),
Clearly... replace 'NameOfYourUserControl' with the actual name of your class that extends the UserControl.
Use a Dictionary.
XAML
<ComboBox ItemsSource="{Binding Dict}"
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Prop}"/>
Code Behind
public Dictionary< ValueType, string > Dict { get; private set; }
private ValueType _prop;
public ValueType Prop
{
get{ return _prop }
set
{
_prop = value;
NotifyPropertyChanged( "Prop" ); // Implement INotifyPropertyChanged
}
}
public ViewModel()
{
Dict = new Dictionary< ValueType, string >()
{
{ value1, string1 },
{ value2, string2 },
{ value3, string3 }
};
}

Categories