ListBox.ItemsSource binding in code and in xaml - wpf

I wrote simple code like
public ObservableCollection<string> Names …
public Window1()
{
PutInDataIntoNames();
InitializeComponent();
this.listBox1.ItemsSource = Names;
}
and in xaml
<Grid>
<ListBox Margin="10,11,10,16"
Name="listBox1"
Background="Black"
Foreground="Orange"
/>
</Grid>
Then I wanted to set ItemsSource property in xaml. In order to do that I wrote the following:
ItemsSource="{Binding Path=Names}"
Unfortunately, it doesn’t work. Could you explain why and how to do that right?

If you only specify the binding path the binding engine will try to navigate the path starting from the current DataContext so ItemsSource="{Binding Path=Names}" does not work like this, there are a lot of different things to keep in mind especially when doing more complex things.
The single most important article that everyone who is new to DataBinding should read is the Data Binding Overview on MSDN
To get back to your binding, if you want to do it completely in XAML you can do that as well, you just need to make the Window your source somehow, either by referencing it directly or relatively or by setting it up as the DataContext.
1 - Direct Reference:
<Window Name="Window"
...>
<Grid>
<ListBox ...
ItemsSource="{Binding ElementName=Window, Path=Names}"
.../>
</Grid>
</Window>
2 - Relative Reference
<Grid>
<ListBox ...
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Names}"
.../>
</Grid>
3 - Setting up the DataContext
<Window ...
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<Grid>
<ListBox ...
ItemsSource="{Binding Path=Names}"
.../>
</Grid>
</Window>

Do this in code behind
public Window1()
{
PutInDataIntoNames();
InitializeComponent();
DataContext = this;
}
and in XAML
<Grid>
<ListBox ItemsSource="{Binding Names}"
Margin="10,11,10,16"
Name="listBox1"
Background="Black"
Foreground="Orange"
/>
</Grid>
Ideally you should follow MVVM design to isolate data from code behind.

It seems that your Names might be a field. You can ONLY bind to public properties

Related

Assign different ViewModels to one UserControl

I have MainWindow.xaml page with it's MainViewModel
and would like to add 2 SidePanels using one UserControl, but it should have different ViewModels.
MainViewModel alredy has 2 properties with created SidePanelViewModels:
public MainViewModel()
{
LeftSidePanel = new SidePanelViewModel(PanelSides.Left);
RightSidePanel = new SidePanelViewModel(PanelSides.Right);
}
How to set objects in this properties as DataContext for each UserControl in xaml?
Something like this doesnot work:
<Window DataContext="{Binding MainViewModel, Source={StaticResource Locator}}">
...
<Grid Visibility="{Binding RightSidePanel.PanelVisibility}" Grid.Column="4" Grid.Row="2" >
<v:SidePanelViev DataContext="{Binding RightSidePanel}" />
</Grid>
</Window>
I broke all the brains thinking how to do it, Please help
ps.
Or please suggest any other approach to reach the same target..
I have solved my problem by adding both instances of SidePanelViewModel as Content of ContentControl
<Window DataContext="{Binding MainViewModel, Source={StaticResource Locator}}">
...
<Grid Visibility="{Binding RightSidePanel.PanelVisibility}" Grid.Column="4" Grid.Row="2" >
<ContentControl Content="{Binding RightSidePanel}"></ContentControl>
</Grid>
</Window>
and adding new Window.Resource what binds all classes of type SidePanelViewModel to be visualised using SidePanelViev
<Window.Resources>
<DataTemplate DataType="{x:Type vm:SidePanelViewModel}">
<v:SidePanelViev></v:SidePanelViev>
</DataTemplate>
</Window.Resources>
This works, but if somebody has better ideas, please do not hesitate to post them, I am not sure that my decision is good one

Binding code-behind property of a wpf UserControl

I am trying to create a Wpf UserControl with a variable number of buttons.
In the code behind public string[] MenuItems { get; set; } contains the Text (Content) of the buttons, so every item in the array should correspond to one button.
I tried:
<UserControl x:Class="MyApp.Controls.MenuButtons"
xmlns:m="clr-namespace:MyApp.Controls"
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"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<DockPanel LastChildFill="False"
Background="{StaticResource ControlBackground}"
DockPanel.Dock="Top"
Height="35"
Margin="5,0,0,0">
<ItemsControl ItemsSource="{Binding MenuItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}"
Style="{StaticResource MenuButton}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
</UserControl>
Using the control in a window like this:
<c:MenuButtons MenuItems="..."></c:MenuButtons>
Gives the error:
The member "MenuItems" is not recognized or is not accessible.
MenuItems is sometimes recognized in xaml intellisense, sometimes not.
The window has iself as datacontext:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Your MenuItems property should be a DependancyProperty in order to use it as Binding Target.
The type should be string[] not string.
static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register("MenuItems", typeof(string[]), typeof(MenuButtons), new PropertyMetadata(null));

WPF: Set UserControl DataContext

I have the following MainWindow that lays out a left side navigation panel and a right side display area (both of these are UserControls).
Can someone explain how to assign the DataContext of the navigation panel (LinksView.xaml) to that of LinksViewModel.cs. I would like to bind a Command (BtnCompanyClickCommand) to the button and define BtnCompanyClickCommand in LinksViewModel.cs.
I have tried various methods that I found on StackOVerflow to set the DataContext but none of these solutions seem to work (binding RelativeSource, naming view and binding to name, etc.).
MainWindow.xaml
<StackPanel Orientation="Horizontal">
<vw:LinksView DataContext="{Binding RelativeSource={RelativeSource Self}}"/>
<ContentControl Content="{Binding CurrentUserControl}" />
</StackPanel>
LinksView.xaml
<StackPanel Orientation="Vertical">
<Button Content="Company" Width="75" Margin="3" Command="{Binding ElementName=Links,Path=BtnCompanyClickCommand}" />
</StackPanel>
FormsDictionary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:SidekickAdmin.ViewModel"
xmlns:vw="clr-namespace:SidekickAdmin.View">
<DataTemplate DataType="{x:Type vm:CompanySummaryViewModel}">
<vw:CompanySummaryView>
<ContentControl Content="{Binding }" />
</vw:CompanySummaryView>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:LinksViewModel}">
<vw:LinksView />
</DataTemplate>
</ResourceDictionary>
EDIT
So I finally came across this explanation of how to set the DataContext of a UserControl which has to be done on the first child item of the UserControl.
Here is the modified LinksView.xaml that works.
<StackPanel Orientation="Vertical">
<StackPanel.DataContext>
<vm:LinksViewModel /> <!-- Bind the items in StackPanel to LinksViewModel -->
</StackPanel.DataContext>
<Button Content="Company" Width="75" Margin="3" Command="{Binding BtnCompanyClickCommand}" />
</StackPanel>
However, I am still not clear on why I have to set the DataContext of the child element and not the UserControl and why the DataTemplate for LinksView (set in FormsDictionary.xaml) doesn't tie into the DataContext of LinksViewModel. Any explanation would be appreciated.
First you have to refer to your DataContext (LinksViewModel.cs) in your XAML code.
You can do that either by directly instantiating it or use a ResourceDictionary. In the latter case you instantiate your DataConext either inside some .cs file or inside the ResourceDictionary .xaml file and store it in a named ResourceDictionary where you can find the reference later.
Second you simply have to associate the DataContext property of a View element like your LinksView.xaml with the corresponding DataContext.
This is pretty high-level and without any code but that's the basic idea behind it.
there should be an instance of LinksViewModel in MainWindowViewModel:
MainWindowViewModel.cs:
class MainWindowViewModel
{
public MainWindowViewModel()
{
LinksVM = new LinksViewModel();
}
public LinksViewModel LinksVM { get; private set; }
}
MainWindow.xaml
<StackPanel Orientation="Horizontal">
<vw:LinksView DataContext="{Binding LinksVM}"/>
<ContentControl Content="{Binding CurrentUserControl}" />
</StackPanel>
LinksView.xaml
<StackPanel Orientation="Vertical">
<Button Content="Company" Width="75" Margin="3" Command="{Binding BtnCompanyClickCommand}" />
</StackPanel>
since LinksView is explicitly created in MainWindow, there is no need in DataTemplate - it can be removed
<DataTemplate DataType="{x:Type vm:LinksViewModel}">
<vw:LinksView />
</DataTemplate>

ItemsControl button click command

I need some quick help which is a road blocker for me now. I have Button in ItemsControl and I need to perform some task on Button click. I tried adding Command to Button in ItemsControl DataTemplate but its not working. Can anyone suggest how to proceed further.
<UserControl.Resources>
<DataTemplate x:key="mytask">
<TextBox Grid.Row="5" Grid.Column="2" Text="{Binding Path=PriorNote}" Grid.ColumnSpan="7" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,5" Width="505" Foreground="Black"/>
<StatusBarItem Grid.Row="2" Grid.Column="8" Margin="8,7,7,8" Grid.RowSpan="2">
<Button x:Name="DetailsButton" Command="{Binding CommandDetailsButtonClick}">
</DataTemplate>
</UserControl.Resources>
<Grid>
<ItemsControl Grid.Row="1"
ItemsSource="{Binding ListStpRules}"
ItemTemplate="{StaticResource myTaskTemplate}" Background="Black"
AlternationCount="2" >
</ItemsControl>
</Grid>
and in ViewModel I have implemented code for Command. And its not working. Please suggest any solution for me to proceed further
The DataContext of each item in your ItemsControl is the item in the collection the ItemsControl is bound to. If this item contains the Command, your code should work fine.
However, this is not usually the case. Typically there is a ViewModel containing an ObservableCollection of items for the ItemsControl, and the Command to execute. If this is your case, you'll need to change the Source of your binding so it looks for the command in ItemsControl.DataContext, not ItemsControl.Item[X]
<Button Command="{Binding
RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}},
Path=DataContext.MyCommand}" />
If your ViewModel has a property of type ICommand you can bind the Button's Command property to that:
XAML:
<DataTemplate DataType="{x:Type my:FooViewModel}">
<Button Content="Click!" Command="{Binding Path=DoBarCommand}" />
</DataTemplate>
C#:
public sealed class FooViewModel
{
public ICommand DoBarCommand
{
get;
private set;
}
//...
public FooViewModel()
{
this.DoBarCommand = new DelegateCommand(this.CanDoBar, this.DoBar);
}
}
Read this:
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Implement a class similar to RelayCommand in the above article. Would make your further MVVM coding easier. :-)
Just a guess. Is CommandDetailsButtonClick defined in a ViewModel, which is DataContext of your UserControl (the one with ListStpRules property)?
DataContext of button in ItemTemplate is an item from ListStpRules, and if you command is not there then binding won't find it.
You can check diagnostic messages from wpf in Output window while debugging your application. It writes there if it can not resolve binding.

How can I bind a property of a user control to a properties of that same control in WPF?

Inside my user control I have a collection call Solutions
public List<string> Solutions { get; set; }
I want to bind that property to a combobox in xaml of that same user control?
I tried
<ComboBox HorizontalAlignment="Left" Margin="21,0,0,41" Name="cbAddSolution" Width="194" Height="21" VerticalAlignment="Bottom"
ItemsSource="{Binding Path=Solutions}" />
but that didn't seem to work.
Name your UserControl in XAML and refer to it from the binding like so:
<UserControl x:Name = "MyUserControl">
<ComboBox HorizontalAlignment="Left" Margin="21,0,0,41" Name="cbAddSolution" Width="194"
Height="21" VerticalAlignment="Bottom"
ItemsSource="{Binding ElementName=MyUserControl, Path=Solutions}" />
</UserControl>
If you want proper binding your UserControl should implement INotifyPropertyChanged for that property or make that property a Dependency Property
Update
Or use RelativeSource if you don't want to name the UserControl
<UserControl>
<ComboBox HorizontalAlignment="Left" Margin="21,0,0,41" Name="cbAddSolution" Width="194"
Height="21" VerticalAlignment="Bottom"
ItemsSource="{Binding Path=Solutions, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</UserControl>
Move the XAML of your control into the Template property, i.e. instead of
<UserControl x:Class="MyUserControl" ...>
...
<ComboBox ... />
...
</UserControl>
use
<UserControl x:Class="MyUserControl" ...>
<UserControl.Template>
<ControlTemplate>
...
<ComboBox ... />
...
</ControlTemplate>
</UserControl.Template>
</UserControl>
Then, you can use TemplateBinding:
<ComboBox ... ItemsSource="{TemplateBinding Solutions}" />
BTW, your question is very similar to this one: Custom UserControl Property used by child element

Resources