I have multiple comboboxes on a WPF window. Each is populated from a ViewModel. I am trying to implement AutoComplete. I have tried using a WPF combobox and telerik combobox. I can't even begin to test whether my autocomplete functionality is workign or not because I cannot type in the combobox. i can only use backspace and spacebar. I have IsEditable set to true. Is there something very basic I am missing?
My xaml from one of the comboboxes
<DockPanel Style="{StaticResource DockPanelStyle}">
<Label Content="Model" DockPanel.Dock="Top"/>
<telerik:RadComboBox x:Name="cboModel" DockPanel.Dock="Bottom" Width="100" ItemsSource="{Binding Path=Models}"
ItemTemplate="{StaticResource ComboBoxCustomTemplate}" IsEditable="True" StaysOpenOnEdit="True"
telerik:TextSearch.TextPath="value"/>
</DockPanel>
The DockPanel above is inside a stackpanel which is inside a grid.
Here is the relevant code from my ViewModel
public void LoadModels()
{
try
{
List<CommonData.Model> model = factory.GetStaticModels();
foreach (CommonData.Model m in model)
{
Models.Add(new CommonData.Model()
{
value = m.value
});
}
}
catch (Exception ex)
{
//leaving this out
}
}
private List<CommonData.Model> _models = new List<CommonData.Model>();
public List<CommonData.Model> Models
{
get
{
return _models;
}
set
{
_models = value;
OnPropertyChanged("Models");
}
}
And finally, this is my Model class(not MVVM Model, the name of the class is Model)
[Serializable]
public class Model
{
private string models;
public string value
{
get;
set;
}
}
Any help/suggestions greatly appreciated. I am very new to WPF and I feel like I am missing something very basic but having spent a good part of 3-4 days on this, its becoming quite ridiculous now.
IsTextSearchEnabled = "True" for standard combobox
Related
I'm mostly new to coding - and I've been stuck on something which probably is very basic:
I'm trying to make a simple picker/drop down menu with numbers ranging from 1-30. And then: I'd like to store the selected number in a variable for use on several other C# pages of the app.
Does anyone know how to do this?
Thanks!
I've gone through a lot of tutorials - but most end up with bugs when I try to adjust the code. Also for many I'm not sure what to adjust.
It's easy to achieve using MVVM pattern. For more information, you could refer to Xamarin.Forms Picker, Xamarin.Forms Data Binding and Part 5. From Data Bindings to MVVM.
I made a small demo for you.
In xaml file, define a Picker. Use the ItemsSource and SelectedItem property. Also we add a new button, the Command property of which is binded to SelectedCommand in the viewmodel.
<Picker x:Name="mypicker"
ItemsSource="{Binding ItemCollection}"
SelectedItem="{Binding SelectedItem}" />
<Button x:Name="mybutton" Command="{Binding SelectedCommand}" BackgroundColor="Yellow" Text="button1" />
In MainPage.xaml.cs file, set the BindingContext:
this.BindingContext = new MainPageViewModel();
In MainPageViewModel.cs file:
public class MainPageViewModel
{
int participantsturn = 1;
public int SelectedItem { get; set; } // you can access the picker value through this property
public ObservableCollection<int> ItemCollection { get; set; }
public MainPageViewModel()
{
ItemCollection = new ObservableCollection<int>();
CreateCollection(); //generate ItemSource for the picker
}
public Command SelectedCommand
{
get
{
return new Command(() =>
{
if (participantsturn == SelectedItem)
{
Console.WriteLine("yes!!!!!!!!!!!");
}else
{
Console.WriteLine("no!!!!!!!!!!!!");
}
});
}
}
private void CreateCollection()
{
var numList = Enumerable.Range(1, 30).ToList();
ItemCollection = new ObservableCollection<int>(numList);
}
}
Hope it works for you. If you still have any question, feel free to ask.
I have a MVVM application which has a WPF Grid which contains other embedded WPF Grids and at the same time, each of them contain some fields (WPF TextBlocks).
Very simplified example - View:
<Grid>
<Grid>
// Row definitions
// Colum definitions
<TextBlock Grid.Row="3" Grid.Column="0"
Text="{Binding Path=SomeField1}" />
<Grid>
<Grid>
// Row definitions
// Colum definitions
<TextBlock Grid.Row="0" Grid.Column="1"
Text="{Binding Path=SomeField2}" />
<Grid>
</Grid>
Each of these TextBlocks are bound to a string properties defined in view model.
View model (It implements INotifyPropertyChanged):
private string _someField1;
public string SomeField1
{
get return _someField1;
set
{
if (_someField1 == value) return;
_someField1 = value;
OnPropertyChanged("SomeField1");
}
}
private string _someField2;
public string SomeField2
{
get return _someField2;
set
{
if (_someField2 == value) return;
_someField2 = value;
OnPropertyChanged("SomeField2");
}
}
Then I have a model, I mean, a class with some public properties that is filled in by one process once data is obtained from a device. This class contains exactly the same properties as those defined in the view model.
Model:
public class MyModel
{
private string _someField1;
public string SomeField1
{
get return _someField1;
set
{
if (_someField1 == value) return;
_someField1 = value;
}
}
private string _someField2;
public string SomeField2
{
get return _someField2;
set
{
if (_someField2 == value) return;
_someField2 = value;
}
}
}
Later from view model I extract the data from this class (model), and I assign the values of those properties to the matching properties in view model. Finally, since view is bound to these properties, then view is correctly updated with values as below example.
View model method which extracts data received:
private void DataReceived(MyModel data)
{
this.SomeField1= data.SomeField1;
this.SomeField2= data.SomeField2;
}
The problem is that I have to define twice the properties, in view model and model. So I want to avoid this, I would like to bind Textblocks directly to properties in model and not defined the properties in view model to avoid redundant code. Or for example, is there any easy way to bind my model (MyModel) to the outer main grid and then textboxes bound to the properties in the view model (similar when bound itemsource in datagrid)?
I would suggest a generic view model:
public class BaseViewModel<TModel>
{
public TModel Model
{
get;
private set;
}
public BaseViewModel(TModel model)
{
this.Model = model;
}
}
Then you can bind to it:
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding Path=Model.SomeField1}" />
I was thinking if below it is ok and respects MVVM pattern. I have thought it after seeing solution proposed by c0d3b34n. I think it is simpler and no need to do interfaces and generic view model. I have checked and it works:
Declare a property in view model:
private MyModel _model;
public MyModel Model
{
get { return _model; }
set
{
_model = value;
OnPropertyChanged("Model");
}
}
Then in the view:
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding Path=Model.SomeField1}" />
... and the same for the rest of TextBlocks.
Finally:
private void DataReceived(MyModel data)
{
this.Model = data;
}
But as said by BionicCode in comments, this solution breaks MVVM pattern.
As the title suggests; I have a combobox using a composite collection to bind to an observable collection using the MVVM pattern.
If I load my model with existing data then the combobox shows the values so I know the binding works. I can add items to the observable collection and they are shown in a data grid so I know the notify property changed events on the observable collection are working. I suspect it is not working because the composite collection is using a "Static Resource" as its source but if I change it to Dynamic Resource then I get the error:
A 'DynamicResourceExtension' cannot be set on the 'Source' property of
type 'Binding'. A 'DynamicResourceExtension' can only be set on a
DependencyProperty of a DependencyObject.
I have searched for days to find a solution and while others have faced similar problems the solutions have yet to solve my problem.
Here is my code for the model:
public class Model : ObservableObject
{
#region Properties
private string name;
public string Name
{
get { return this.name; }
set { this.name = value; }
}
private string balance;
public string Balance
{
get { return this.balance; }
set { this.balance = value; }
}
#endregion
My ViewModel:
public class ViewModel : ObservableObject
{
private ObservableCollection<Model> modelcollection;
public ObservableCollection<Model> ModelCollection
{
get { return modelcollection; }
set
{
modelcollection= value;
RaisePropertyChangedEvent("ModelCollection");
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChangedEvent("Name");
}
}
private string _balance;
public string Balance
{
get { return _balance; }
set
{
_balance = value;
RaisePropertyChangedEvent("Balance");
}
}
And finally the XAML of my view for the combobox:
<ComboBox MinWidth="100" SelectedValue="{Binding combovalue, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Name">
<ComboBox.Resources>
<vm:ViewModel x:Key="CollectionKey"/>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding ModelCollection, Source={StaticResource CollectionKey}, UpdateSourceTrigger=PropertyChanged}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Thank you all so much in advance.
EDIT:
So I have moved in a direction; right or wrong is yet to be decided.
I think I have traced the problem to be outside the combobox itself so more context is needed here.
The comobobox is on the second tab of a tab control. Each tab item has its own data context pointing to its own view model. Data is entered on the first tab and I want that data to show up in the combobox on the second tab.
If I put a combobox on the first tab then that combobox updates with changes in the observable collection as entered on the first tab. So the issue, (I think), is that the combobox on the second tab is trying to bind to two different view models at the same time. One for the items source and a different one for the selected value.
There was a suggestion in another thread to use x:Reference for the data context but I can't seem to figure out the correct syntax for that.
If your still reading this then any help is really appreciated.
In the end I never got the combobox to populate from the other view model. I am still unsure if this is possible or not.
The solution that finally worked for me was to just combine everything I needed for binding into a single view model. It made the view model a bit heavy but cut down a lot on the XAML so I guess that's a win.
In my application, I need to bind a checkbox list to an observable collection. I have seen many examples but I could not find a proper implementation for this and thats why I am posting this question.
The View:
<Grid Name="GrdMain" Background="White">
<ListView Name="lstConditions" VerticalAlignment="Top" Height="150"
ItemsSource="{Binding ConditionsModels}" Margin="0,25,0,0" BorderBrush="Transparent" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding Path=condition}" Margin="8" Style="{StaticResource CheckBoxDefault}"
IsChecked="{Binding hasCondition,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListView>
</grid>
The model:
public class ConditionsModel
{
public int profileId { get; set; }
public string condition { get; set; }
public bool hasCondition { get; set; }
}
The View Model:
public class ConditionsViewModel : INotifyPropertyChanged
{
private ConditionsModel _conditionsModel;
private ObservableCollection<ConditionsModel> _conditionsModels;
public ConditionsModel ConditionsModel
{
get
{
return _conditionsModel;
}
set
{
_conditionsModel = value;
RaisePropertyChanged("ConditionsModel");
}
}
public ObservableCollection<ConditionsModel> ConditionsModels
{
get
{
return _conditionsModels;
}
set
{
_conditionsModels = value;
RaisePropertyChanged("ConditionsModels");
}
}
public ConditionsViewModel(int profileId)
{
ConditionsModel = new ConditionsModel();
ConditionsModels = new ObservableCollection<ConditionsModel>();
ConditionsModels.CollectionChanged += ConditionsModels_CollectionChanged;
GetConditions(profileId);
}
void ConditionsModels_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
RaisePropertyChanged("ConditionsModels");
}
private void GetConditions(int profileId)
{
HealthAssessmentRepository _rep = new HealthAssessmentRepository();
_conditionsModels = _rep.GetConditions(profileId);
}
}
Is this a correct implementation? I need to update the model when the user checks or unchecks the checkbox. But its not raising the propery changed event when the check box is checked or unchecked.Should I implement the INotifyPropertyChanged interface on the model as well?
I have seen many examples, but all of them has different approaches to this and I am confused. Please show the correct implementation of this?
Thanks
I think you have missed the DataType property within DataTemplate. Just refer this
<DataTemplate DataType="{x:Type sampleApp:ConditionsModel}">
Here sampleApp in the namespace reference created within tag. And ConditionsModel is your model class.
You need to implement INotifyPropertyChanged for class ConditionsModel and raise PropertyChangedEvent for the property you want to observe/synchronize, because it is ViewModel as well.
For class ConditionsViewModel, it's the ViewModel of whole ListView, for ConditionsModel, it's the ViewModel of every line. ViewModel can be overlaid. If ConditionsModel is the domain model, my suggestion is that add a new ItemViewModel, because they belong to different layers. It's always better to distinguish the different layers properly.
So I've got a basic view model that functions like so:
// The ICollectionVIew is what my ListBox binds to.
public ICollectionView UserView { get; set; }
// <signup> is a model that's populated from a database representing a signup table
private ObservableCollection<signup> _signup;
public ObservableCollection<signup> Signup
{
get
{
return _signup;
}
set
{
if (_signup != value)
{
value = _signup;
}
OnPropertyChanged("Signup");
}
}
// This is the constructor for the ViewModel
public registrationVM()
{
// entity context Fills up the Model
context.signups.Load();
// The below code fills up the ObservableCollection
var query = context.signups;
_signup = new ObservableCollection<signup>(query);
// And the below code fills up the ICollectionView using the ObservableCollection
UserView = CollectionViewSource.GetDefaultView(_signup);
}
So now instead of binding to the ObservableCollection, I can bind to the ICollection.
<ListBox ItemsSource="{Binding UserView}" DisplayMemberPath="firstName" SelectedItem="{Binding SelectedUser}"/>
This works perfectly in terms of loading my information. But then now comes the issue of navigating. I bound my button Commands to the ViewModel,
<Button x:Name="next" Command="{Binding Next}"/>
And in it's execution Method:
private object Next_CommandExecute(object param)
{
// 'UserView' Is the ICollectionView I declared earlier
return UserView.MoveCurrentToNext();
}
The problem is the button's function doesn't do anything. Same goes for the 'previous' Button. The on screen selected record doesn't change so I'm guessing there's something I'm doing wrong. What exactly is what I've been failing to figure out. Does anyone see where I'm going wrong?
As mentioned in my comment, you need to set IsSynchronizedWithCurrentItem = true on your ListBox
ListBox ItemsSource="{Binding UserView}"
DisplayMemberPath="firstName"
IsSynchronizedWithCurrentItem = true
SelectedItem="{Binding SelectedUser}"/>