I have a List of objects of type MenuModel called MenuList inside my ViewModel. I am using CaliburnMicro framework
I would like to show this list as a list of ToggleButtons that have IsChecked property bound to other object list called SelectedMenusMonday, which is list of type SelectedMenuModel that has only IsSelected property and is the same length as MenuList.
MenuModel looks like this:
public class MenuModel
{
public int MenuKey { get; set; }
public string MenuName { get; set; }
public string Description { get; set; }
}
MenuList:
public List<MenuModel> MenuList
{
get { return _MenuList; }
set => Set(ref _MenuList, value);
}
SelectedMenuModel
public class SelectedMenuModel
{
public bool IsSelected { get; set; }
}
And SelectedMenusMonday list:
private BindableCollection<SelectedMenuModel> _SelectedMenusMonday = new BindableCollection<SelectedMenuModel>();
public BindableCollection<SelectedMenuModel> SelectedMenusMonday
{
get { return _SelectedMenusMonday; }
set => Set(ref _SelectedMenusMonday, value);
}
I am trying to display like this:
<ItemsControl x:Name="MondayMenuList" ItemsSource="{Binding MenuList}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Content="{Binding MenuName}" IsChecked="{Binding Path=DataContext.SelectedMenusMonday.IsSelected, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The MenuList and SelectedMenus Monday get filled from SQL DB. This is the solution i tried, but it does not work. Can someone help me please! I want the ToggleButtons to be "checked" if the item on the SelectedMenusMonday have IsSelected property as true.
Thank you very much!
Name the root element in your view (or wherever you know the DataContext to be correct) and use ElementName binding as shown here:
<UserControl x:Name="view">
<Grid>
<ItemsControl x:Name="MondayMenuList" ItemsSource="{Binding MenuList}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Content="{Binding MenuName}" IsChecked="{Binding ElementName=view, Path=DataContext.SelectedMenusMonday}">
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
Note the x:Name="view" in the UserControl element.
Related
I've created a ListBox with this structure:
<ListBox VerticalAlignment="Stretch"
Background="AliceBlue"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ItemsSource="{Binding EventInfo}">
how you can see I binded the EventInfo property that I valorize behind code. This property have the OnPropertyChange(); implementation as my other properties, and the value setted is got correctly. Anyway, I'm not able to display the binded source:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=League}" />
<TextBlock Text="test" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
now the property League value isn't displayed also the value test. I really don't understand why. The League property exist, and also I've no error in xaml.
What I did wrong?
UPDATE:
public Models.EventInfo EventInfo
{
get { return _eventInfo; }
set
{
_eventInfo = value;
OnPropertyChanged();
}
}
and in the Model
public class EventInfo
{
public string League { get; set; }
public string Date { get; set; }
public string GameWeek { get; set; }
public string GameStart { get; set; }
public string FirstTime { get; set; }
public string SecondTime { get; set; }
public string Stadium { get; set; }
public List<MatchArbiter> Arbiter { get; set; }
}
Try this. You need to populate ItemsSource with a collection, not a single item. Instead of your existing EventInfo property, you need a collection property. I'm going to rename it to EventInfoItems to keep confusion to a minimum.
private ObservableCollection<Models.EventInfo> _eventInfoItems =
new ObservableCollection<Models.EventInfo>();
public ObservableCollection<Models.EventInfo> EventInfoItems
{
get { _eventInfoItems; }
set
{
_eventInfoItems = value;
OnPropertyChanged();
}
}
Now, somewhere, you're going to have to add some items to that collection if you want anything to appear in the list. You could create a few test items in your viewmodel constructor, just for the time being. Like this:
EventInfoItems.Add(new EventInfo { League = "NBA" });
EventInfoItems.Add(new EventInfo { League = "Premier League" });
EventInfoItems.Add(new EventInfo { League = "Serie A" });
XAML
<ListBox
VerticalAlignment="Stretch"
Background="AliceBlue"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ItemsSource="{Binding EventInfoItems}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=League}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Update
Turns out OP may have only one item. If that's the case, a ListBox is unnecessary. A ContentControl is the right control when you've got only one item and you want to display it with a DataTemplate. This XAML will use the original version of the EventInfo property:
public Models.EventInfo EventInfo
{
get { return _eventInfo; }
set
{
_eventInfo = value;
OnPropertyChanged();
}
}
XAML:
<ContentControl
VerticalAlignment="Stretch"
Background="AliceBlue"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Content="{Binding EventInfo}"
>
<ContentControl.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=League}" />
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
I Have some window like:
<Window>
<ItemsControl ItemsSource="{Binding MyItemList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding ViewModelCommand}">My Button</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
This window has the DataContext property defined with an instance of:
public class MyVM
{
public IEnumerable<FooType> MyItemList { get; set; }
public ICommand ViewModelCommand { get; set; }
}
The problem is that the Button.Command binding is not working. I'm guessing that the problem is because my button is inside ItemsControl, so the binding is looking for ViewModelCommand inside of the object of FooType.
So how can I make this bind properly?
The DataContext inside that DataTemplate will be the FooType item; that's what the ItemTemplate is there for: To display each item.
I'm having following classes:
class MyViewModel
{
public List<MyItem> MyItems { get; set; }
public int Width { get; set; }
}
class MyItem
{
public string Name {get; set;}
}
As you see, there's a list of MyItems and Width property in the same class called MyViewModel. How can I bind a single element of that list to a Text property in XAML and Width from ViewModel to XAML's Width property? Here's my try, but I can't at the same time bind those two properties. I mean, I can bind whole list to Text property, but I don't know how could I bind a single item.
<ListView ItemsSource="{Binding MyViewModel}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Height="15" Width="520">
<TextBlock Width="{Binding Width}" Text="{Binding=MyItems.Name(?)}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
You should revise your design, but here is a quick fix: just introduce a readonly property, that returns the first element, so you will have this (assuming MyItems always has at least element, otherwise you will get an exception):
class MyViewModel
{
public List<MyItem> MyItems { get; set; }
public int Width { get; set; }
public MyItem FirstElement { get { return MyItems[0]; } }
}
In your xaml you bind TextBlock to this property:
<ListView ItemsSource="{Binding MyViewModel}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Height="15" Width="520">
<TextBlock Width="{Binding Width}" Text="{Binding=FirstElement}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
A little bit offtopic, but still important: viewmodel classes often implement INotifyPropertyChanged, so that views will be able to update themselves automatically. For the same reason List<T> should be replaced with ObservableCollection<T>.
I have an ItemsControl in which I display different properties and values, with the name on one side and a TextBox on the other side. The ItemsSource is a collection of objects of a custom class, that has Name, Value and PropertyType properties (using reflections propertyinfo)
Now I would like to improve this by being able to detect whether the property is of type bool for example, which would display a checkbox instead of a textbox. Is this possible using a DataTrigger?
I got it semi-working using a Control of which I set the template to a textbox or checkbox according to the type, but when I try to "tab" to the next textbox or checkbox, it focuses the control that has the textbox/checkbox first, and only after another "tab" it focuses the containing textbox/checkbox/..
So if anybody know a solution for this, that would be greatly appreciated!
Use the solution you already have and set the Focusable property to false on the control that wrongly gets tab focus.
You can use DataTemplate to select different View based on Value property type.
View:
<ItemsControl ItemsSource="{Binding Path=Options}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<DataTemplate DataType="{x:Type System:Boolean}">
<CheckBox IsChecked="{Binding Path=.}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Path=.}"/>
</DataTemplate>
</DataTemplate.Resources>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
<ContentControl Content="{Binding Path=Value}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ViewModel:
public class MainViewModel
{
public ArrayList Options { get; set; }
public MainViewModel()
{
Options = new ArrayList();
Options.Add(new TextProperty());
Options.Add(new BoolProperty());
}
}
public class TextProperty
{
public string Name { get; set; }
public string Value { get; set; }
public TextProperty()
{
Name = "Name";
Value = "Default";
}
}
public class BoolProperty
{
public string Name { get; set; }
public bool Value { get; set; }
public BoolProperty()
{
Name = "IsEnabled";
Value = true;
}
}
I have placed a Radio button in a listbox content and binded it with list of QuizOption1
binding is working fine and showing the radio button checked if the property IsSelected is passed as true. the class definition is given below.
class QuizOption1
{
public int QuizID { get; set; }
public int QuizOptionID { get; set; }
public string Description { get; set; }
public bool IsSelected { get; set; }
}
While checking for the checked items, i am using following code
var lstItems = (List<QuizOption1>)lst.ItemsSource;
var selItems = lstItems.Where(op => op.IsSelected == true).FirstOrDefault();
The binding is as follows.
<ListBox Name="lst1" Grid.Row="1" >
<ListBox.ItemTemplate >
<DataTemplate >
<RadioButton
Foreground="#333333"
Background="#ffededed"
Tag="{Binding QuizOptionID}"
Content="{Binding Description}"
IsEnabled="True"
GroupName="{Binding QuizID}"
IsChecked="{Binding Path=IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
but selItems is always null. Can anyone tell me why? Thanks in advance.
The answer is very simple, i need to add the Mode=TwoWay attribute in binding and binding looks like following.
Thanks anyways.
IsChecked="{Binding IsSelected, Mode=TwoWay}"/>