I want to have a listbox, that allows the user to fetch lets say 20 items from the DB and displays a hint on the last row of the listbox if there are more items to be fetched. When the user clicks on this last row, additional items should be retrieved from the DB, until there aren't any more and the last line displays this information.
First:
listitem1
listitem2
...
listitem19
listitem20
Button: <get_more>
after button press:
listitem1
listitem2
...
listitem39
listitem40
Info: <no more items>
Could all this be done in XAML only?
What would be the best solution to implement this?
Dude -- Everything can be done with XAML :D
Following a MVVM approach, I'd recommend you to do the following:
1/ Getting started: A DockPanel
<DockPanel LastChildFill="True">
<Button DockPanel.Dock="Bottom" />
<ListBox />
</DockPanel>
2/ Bind your ListBox to an ObservableCollection in your ViewModel:
<ListBox ItemsSource="{Binding ListElements}" />
In the ViewModel:
private ObservableCollection<String> _listElements;
public ObservableCollection<String> ListElements
{
get { return _listElements; }
set { _listElements = value; }
}
3/ Bind your Button's content to a predefined String:
<Button Content="{Binding ButtonString}" />
In the ViewModel:
public String ButtonString
{
get
{
//There, define if there are any more things to display
}
}
4/ Your Button fires a Command launching a method, let's say GetMore() :
<Button Content="{Binding ButtonString}" Command="{Binding GetMoreCommand} />
In ViewModel:
private void GetMore()
{
//append to the _listElements new elements from the list
//Update the ButtonString if there are no more elements
}
And there you go!
(you can also, if needed, define a button removing things from the ObservableCollection for example)
Related
I'm quite new to WPF/MVVM and have a lot to learn still, but I'm hitting an issue at the moment that i can't seem to find good answers for. Most probably because I'm asking the wrong questions.
What I have:
I have a main form with some buttons which load user controls. One of these user controls contains a TabControl.
This TabControl has a manually populated first Tab, which I've excluded from below snippet, but all other tabs should be populated with another user control, which will load database data depending on its viewmodel constructor.
XAML:
<TabItem Header="Two"
Name="Two"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
<ContentControl cal:View.Model="{Binding LoadedControl}"></ContentControl>
</TabItem>
<TabItem Header="Three"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
<ContentControl cal:View.Model="{Binding LoadedControl}"></ContentControl>
</TabItem>
<TabItem Header="Four"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
<ContentControl cal:View.Model="{Binding LoadedControl}"></ContentControl>
</TabItem>
C#
private DocumentTemplateControlViewModel _loadedControl;
public DocumentTemplateControlViewModel LoadedControl
{
get { return _loadedControl; }
set
{
if (value == _loadedControl)
return;
_loadedControl = value;
NotifyOfPropertyChange(() => LoadedControl);
}
}
public int SelectedTabIndex
{
get
{
return _selectedTabIndex;
}
set
{
Task.Run(() => LoadData());
_selectedTabIndex = value;
LoadedControl = new DocumentTemplateControlViewModel(Templates, _selectedTabIndex);
}
Now, This works as I intended it to work for Tab Two, but if I add the same line of
<ContentControl cal:View.Model="{Binding LoadedControl}">
to Tab Three,Four,etc.. (as I've done in the XAML snippet above) it will only work on the last tab that I've added the binding to, and Tab two,three will be blank.
I also tried to achieve the same thing with Caliburn Micro ActivateItem but this means i can also only declare one ActiveItem in my TabControl XAML as well.
TLDR: What is the best way to dynamically show a new user control viewmodel within a tabitem?
Thanks so much
Derive your view model from Conductor<IScreen>.Collection.OneActive and add the DocumentTemplateControlViewModel objects that you want to bind to the tabs to the Items property:
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
{
public ShellViewModel()
{
Items.Add(new DocumentTemplateControlViewModel { DisplayName = "1" });
Items.Add(new DocumentTemplateControlViewModel { DisplayName = "2" });
Items.Add(new DocumentTemplateControlViewModel { DisplayName = "3" });
}
}
DocumentTemplateControlViewModel must implement IScreen and the easiest way to do this is to derive from Screen:
public class DocumentTemplateControlViewModel : Screen
{
}
In the XAML you could then simply add a TabControl with a ContentTemplate, e.g.:
<TabControl Name="Items">
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
You may replace the TextBlock with a UserControl or any other UI element.
I have a user control (WaypointInfoControl) that I wrote that has a dependency property named TheGraphic as shown here:
public Graphic TheGraphic
{
get { return (Graphic)GetValue(TheGraphicProperty); }
set { SetValue(TheGraphicProperty, value); }
}
public static readonly DependencyProperty TheGraphicProperty =
DependencyProperty.Register("TheGraphic", typeof(Graphic), typeof(WaypointInfoControl), new PropertyMetadata(default(Graphic)));
I have a viewmodel that has a Waypoints property defined like this:
private ObservableCollection<Graphic>_Waypoints = new GraphicCollection();
public ObservableCollection<Graphic> Waypoints
{
get { return _Waypoints; }
set { RaiseAndSetIfChanged(ref _Waypoints, value); }
}
In my xaml, I have a ListView that I want to populate with Waypoints:
<ListView ItemsSource="{Binding Waypoints}" >
<ListView.ItemTemplate >
<DataTemplate >
<controld:WaypointInfoControl TheGraphic="????" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
How do I bind TheGraphic to the individual item in the ListView that it represents?
Your ItemsSource is bound to a collection of Graphic objects which means that the DataContext for each item in your ListView will be a single Graphic object. Since the DependencyProperty that you are looking to bind to is looking for the Graphic object you will just want to bind to the entire DataContext, you achieve this by using the binding markup extension without specifying a path (this just causes the binding to pull in the entire DataContext which in your case is the Graphic object that you are looking for).
So this should work:
<ListView ItemsSource="{Binding Waypoints}" >
<ListView.ItemTemplate >
<DataTemplate >
<controld:WaypointInfoControl TheGraphic="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have datagrid with a delete button XAML looks like:
<sdk:DataGridTemplateColumn Header="Del/Tgl" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete"
Command="{Binding DeleteRowCommand}"
CommandParameter="{Binding Column}"
/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
I implemented ICommand as DelegateCommand by copying the code from John Papa. I added a public property to my ViewModel :
public ICommand DeleteRowCommand {get;set;}
In the constructor of my viewModel I set the command:
this.DeleteRowCommand = new DelegateCommand(onDelete, CanDelete);
and finally defined the onDelete, and CanDelete:
private void onDelete(object param)
{
// Get the Column Name
string strColumnName = param as string ?? string.Empty;
}
private bool CanDelete(object param)
{
// If we ae here we can delete the row
return true;
}
Everything works on my Silvelight grid but the delete button click, and I never go to onDelete function. What am I doing wrong?
Basically Command binding will look for DeleteRowCommand property inside the Object ( I mean the list of object that is binded as ItemSource to the datagrid). So you need to set the Source of Binding or use relativesource if you are using SL5.
Cheers!
Vinod
I have on checkbox inside telerik combo control. If User click on "All" option from checkbox list then I want select all checkboxs.
checkbox values.
My Sample code is below.
<telerik:RadComboBox Name="rcbDays" Grid.Row="1" Grid.Column="1" Width="200" HorizontalAlignment="Left" ItemsSource="{Binding MonthDaysList}" VerticalAlignment="Center" >
<telerik:RadComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="chkDays" Content="{Binding DaysText}"
Tag="{Binding DaysValue}" Checked="chkDays_Checked" />
</StackPanel>
</DataTemplate>
</telerik:RadComboBox.ItemTemplate>
</telerik:RadComboBox>
private void chkWeeks_Checked(object sender, RoutedEventArgs e)
{
//Here I want code for selecting all checkboxes.
}
The items that you bound the ComboBox to should have a property like IsSelected, then you should bind IsChecked of the data-template CheckBox to that. Then you just need to iterate over the source collection and set IsSelected=true on all items.
e.g.
public class MyClass : MyBaseClass // Whatever you may have called it,
{
public bool IsSelected { ... }
public string DaysText { ... }
//...
}
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding DaysText}" Tag="{Binding DaysValue}" />
</StackPanel>
</DataTemplate>
//In the handler that is supposed to select all
foreach (var item in MonthDaysList) item.IsSelected = true;
Of course the property needs to have change notifications.
(Also a note on usability: I do not thing that ComboBoxes should contain CheckBoxes, if you need multiple item selection use a ListBox)
You need to take one more property isSelected as said by H.B.
add IsChecked="{Binding IsSelected}" to CheckBox tag in xaml file. Create one property in the appropriate class i.e. public bool isSeleted.......
When you get in to event chkWeeks_Checked() in this function get reference of the ComboBox item source like objList = (TypeCastYourClassType)YourComboBox.ItemSource;... Now the objList contains all checkbox items. Iterate through objList collection and get isSeleted property for each and every single item and that's done....
In your case
MonthDayList = (TypeCastYourClassType)rcbDays.ItemSource;
for(int i=0;i<MonthDayList.Count;i++)
{
MonthDayList[i].isSelected = true;
}
Here is some good discussion for allowing multiple values to be selected in the telerik combobox.
It uses checkbox within combobox
http://codedotnets.blogspot.in/2012/02/checkboxes-in-comboxes-to-allow.html
Thanks :)
I am writing a WPF application where where i need to display custom file iformation which consists of field name & its value. I generate a grid rumtime with label & textboxes. I display the field name in label & field value in textbox(i want it to be editable). & each time file selection changes, number of field change & so the grid columns & rows. Right now I am generating this grid in code behind . Is there any way i can do it in XAml with view model.
This is pretty easy to do with an ItemsControl. If you ViewModel exposes a list of metadata objects, say a class like this:
public class FileMetaData : INotifyPropertyChanged
{
private string name;
private string value;
public event PropertyChangedEventHandler PropertyChanged = (o, e) => { };
public string Name
{
get { return name; }
set
{
name = value;
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
public string Value
{
get { return value; }
set
{
this.value = value;
PropertyChanged(this, new PropertyChangedEventArgs("Value"));
}
}
}
Then, your ViewModel would expose it as an ObservableCollection (so WPF knows when new items are added or removed):
public class MyViewModel
{
...
public ObservableCollection<FileMetaData> Files { get; private set; }
...
}
Then, your view would use an ItemsControl with an ItemTemplate to display it:
<ItemsControl ItemsSource="{Binding Files}" Grid.IsSharedSizeScope="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="one" />
<ColumnDefinition Width="Auto" SharedSizeGroup="two" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" />
<TextBox Grid.Column="1" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note that I'm setting Grid.IsSharedSizeScope to true on the ItemsControl, so the columns will align. If you have a lot of data, you'll probably want to wrap this in a ScrollViewer (or better retemplate the ItemsControl to have one).
I'm not sure why you're creating this grid at runtime. You should look into using a standard presentation method such as a <ListBox> with a custom item template. Always look to use declaritive definition of your UI (within the XAML) instead of the codebehind.
I've got a blog post on creating a checked listbox that shows some of the details, but you should be able to find other good examples out there as well.