DisplayMemberPath not displaying Property - property not found in 'ViewModel' - c#

My MainView has a ViewModel called MainViewModel. MainViewModel creates a dialog and I want the dialogs ViewModel to be the already existing MainViewModel
To create the dialog from the MainViewModel I do
var MyInnerDlg = new MyInnerDlgView();
MyInnerDlg.DataContext = this;
MyInnerDlg.ShowDialog();
In the dialog I have a ListBox which I bind to a collection from my MainViewModel
public ObservableCollection<MyItemViewModel> MyList { get; set; }
XAML of the dialog
<Border Margin="5" BorderThickness="2">
<ListBox ItemsSource="{Binding MyList}" DisplayMemberPath="{Binding MyList.Name}" />
</Border>
The Name property is in MyItemViewModel. With the above code I get the error:
Name property not found in MainViewModel.
How can I refer to each of the items Name property?

DisplayMemberPath should probably not be a Binding. Change it to the property name of the property that you want to display, i.e. "Name"
<ListBox ItemsSource="{Binding MyList}" DisplayMemberPath="Name" />
Also, a general suggestion is not to have public setters on lists, since you can get unindented behavior. Instead, use a backing field and remove the setter.

Try changing :
<ListBox ItemsSource="{Binding MyList}" DisplayMemberPath="{Binding MyList.Name}">
To:
<ListBox ItemsSource="{Binding MyList}" DisplayMemberPath="{Binding Name}">
Or try adding:
<Page.Resources>
<local:MyItemViewModel x:Key="DataContext" />
</Page.Resources>
<ListBox DataContext="{StaticResource DataContext}" ItemsSource="{Binding MyList}" DisplayMemberPath="{Binding MyList.Name}"> </ListBox>
Usually i add a ViewModel in the xaml file itself.
<Page.Datacontext>
<local:MyItemViewModel/>
</Page.Datacontext>

Related

How to access data from ViewModel in ItemsSource tag

I'm making TabControl that can change dynamically using ItemsSource tag.
I want to know the way to access ViewModel data in ItemsSource tag.
I searched through the Internet. but I couldn't find the answer.
CODE
public class ViewModel
{
// this will be used in ItemsSource
private ObservableCollection<ActiveButton> _allExecuteButtonInfos = new ObservableCollection<ActiveButton>();
public ObservableCollection<ActiveButton> AllExecuteButtonInfos
{
get { return _allExecuteButtonInfos; }
set {
_allExecuteButtonInfos = value;
OnPropertyChanged();
}
}
// I want to get this data in ItemsSource
private List<string> _boardNameList = new List<string>();
public string BoardNameList
{
get { return _boardNameList; }
set {
_boardNameList = value;
OnPropertyChanged();
}
}
}
XAML
<Grid>
<TabControl Background="#FF292929" ItemsSource="{Binding AllExecuteButtonInfos}">
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto">
<Grid VerticalAlignment="Stretch" Margin="0,0,0,0" >
<ComboBox Width="334" Margin="0,0,0,0" Grid.Column="1" Grid.Row="1" Height="22" VerticalAlignment="Top"
<!-- I want to get data from ViewModel not in ItemsSource(AllExecuteButtonInfos) -->
<!-- eg) VM:BoardNameList, ViewModel.BoardNameList etc -->
ItemsSource="{Binding BoardNameList, Mode=TwoWay , UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedBoard, Mode=TwoWay}"/>
</Grid>
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
I hope I can find the answer.
Thank you.
You could bind to the DataContext, i.e. the view model, of the parent TabControl using a RelativeSource:
<ComboBox ...
ItemsSource="{Binding DataContext.BoardNameList, RelativeSource={RelativeSource AncestorType=TabControl}}" />
Note that it's pointless to set the Mode of an ItemsSource binding to TwoWay since the control never sets the property. It's also meaningless to set the UpdateSourceTrigger to PropertyChanged in this case for the same reason.
I am not sure where you've defined the data context but I suppose that it's somewhere above the first 'Grid' markup. Something like this?
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
Then you have to somehow refer to the Datacontext of the window. You can do it this way
<ComboBox
ItemsSource="{Binding DataContext.BoardNameList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" />
if the name of your view is not 'MainWindow', you have to change it to the view name where you have that code.
One of the best ways is to create a UserControl for each model and then put data templates in TabControl.Resources with DataType specified for all types you could put in ItemsSource - you get full customization of the view with nice seperation of XAML files.
<Grid>
<TabControl Background="#FF292929" ItemsSource="{Binding AllExecuteButtonInfos}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type MyViewModel1}">
<MyViewModel1_View ViewModel="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type MyViewModel2}">
<MyViewModel2_View ViewModel="{Binding}"/>
</DataTemplate>
</TabControl.Resources>
</TabControl>
</Grid>
I'm going from memory, so the binding may be done differently, but that's the basic idea.
That, or you use some kind of ViewResolver as the only item in the TabControl (something like this)
Basically, go even more MVVM :)
Provided that the DataContext of your view is set correctly to your ViewModel and AllExecuteButtonInfos is indeed available in your view, you can use a RelativeBinding to access properties which are not in the DataContext of your current scope.
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.BoardNameList}" />
With that, you are leaving the implicit DataContext of the DataTemplate, which is ActiveButton and access the object of the specified type via AncestorType. From there you can set a Path to the DataContext of the UserControl, which is, in your case, an object of the class ViewModel.
Imaging you are climbing up a ladder. From the ComboBox object up to your UserControl, from where you can access all underlying properties.

WPF Binding directly to the DataContext

Is there a keyword to directly bind to the DataContext and not to an attribute of it?
I heard about the workaround with a Self Object. My problem is that I open a Window, and give an ObservableCollection as argument, which is set to the DataContext.
Here the WPF(xaml.cs) ctor
public Depot(ObservableCollection<ObservableCollection<ItemManager.Item>> totalDepot)
{
this.FullDepotList = totalDepot;
this.DataContext = FullDepotList[1];
InitializeComponent();
}
The XAML Code snippet where I would preferably bind to the DataContext directly or to "this":
<WrapPanel>
<ListBox
ItemsSource="{Binding this, UpdateSourceTrigger=PropertyChanged}"
ItemTemplate="{DynamicResource ItemWithCoolTooltipTemplate}"
Focusable="False">
</ListBox>
</WrapPanel>
To bind directly to the DataContext and not to an attribute of it, don't write any binding Path. Make it just {Binding}. UpdateSourceTrigger=PropertyChanged is not needed because ItemsSource doesn't change from view.
<ListBox
ItemsSource="{Binding}"
ItemTemplate="{DynamicResource ItemWithCoolTooltipTemplate}"
Focusable="False">
</ListBox>
alternatively use Path=. to code "bind entire DataContext here" requirement
<ListBox
ItemsSource="{Binding Path=.}"
ItemTemplate="{DynamicResource ItemWithCoolTooltipTemplate}"
Focusable="False">
</ListBox>
any tricks with RelativeSource/ElementName are usually necessary to change binding source. In this case DataContext (binding source) is simply inherited from parent Window.
You can try the following trick.
Add name property to your Window - <Window ... Name="myWindow" ...>
Use such a construction to bind to the property or whatever you need - <ListBox ItemsSource="{Binding Path=DataContext, ElementName=myWindow}" ... />

xaml inside xaml. How to bind controls

I have xaml inside an xaml. The inside xaml has some bindings which are giving some problems. To explain here is my code
Main xaml
<TabItem Header="Configuration" DataContext="{Binding ComponentsVM}">
<Grid>
<ListBox ItemsSource="{Binding SomeList}" DisplayMemberPath="Name" SelectedItem="{Binding SomeComponent}" SelectedIndex="0"/>
<ig:MyInsideXamlElement Content="{Binding MyUserControl}" DataContext="{Binding}" />
</Grid>
</TabItem>
The inside xaml is
<Grid>
<TextBox Text="{Binding MySearchPath}"/>
</Grid>
The MyUserControl property displays my binding of UserControl without problems. But the MySearchPath property does not get updated with entity framework class. I suspect the binding of my inner xaml(MySearchPath) does not get resolved because the whole tab item's datacontext is ComponentsVM. Is there any way to give a second datacontext to the inner xaml?

How to (is it possible to) set property of user control from outside?

This is my XAML:
<UserControl x:Class="SearchResultsBox">
<ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding Selected}"
Style="{StaticResource ListBoxStyle1}"
ItemContainerStyle="{StaticResource SearchItemContainerStyle}"
Background="{StaticResource DefaultBackground}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent">
<local:Forecast_SearchResults_ListView_Data/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl x:Class="SearchResultsBox">
I want to be able to reuse this listbox and just slap on a new datatemplate from the external context:
<local:SearchResultsBox>
<DataTemplate = {ForecastDataTemplate}/>
</local>
And it will put this DataTemplate into the ListBox.ItemTemplate property. Is this even possible? If so, how? If not, is there another way to achieve a similar effect?
you may use as follows
<local:SearchResultsBox ItemTemplate="{StaticResource ForecastDataTemplate}" />
and you can wire up the property to the underlying ListBox
eg
add a name to listbox
<ListBox x:Name="list" ... />
add a property wiring
public DataTemplate ItemTemplate
{
get { return list.ItemTemplate;}
set { list.ItemTemplate = value;}
}

Binding Listbox to a DataTable using Binding

I'm new to this and Google isn't helping me this time. I was able to follow some examples and populate a DataGrid and modify a database, but ListView is giving me a problem. Here is my class:
public class GlobalDataviews : INotifyPropertyChanged
{
...
//Billable data table
//Populated elsewhere with "SELECT ID, Value FROM BillableTable;"
private DataTable mBillable;
public DataView Billable()
{
return mBillable.DefaultView;
}
}
Here is my XAML snippets:
<Window.Resources>
<ObjectDataProvider x:Key="GlobalDataviews" ObjectType="{x:Type local:GlobalDataviews}" />
<ObjectDataProvider x:Key="BillableData" ObjectInstance="{StaticResource GlobalDataviews}" MethodName="Billable" />
</Window.Resources>
And now for my ListView:
<ListBox Name="listBox1" DataContext="{StaticResource BillableData}" SelectedValuePath="ID" DisplayMemberPath="Value"/>
I'm probably missing something very simple. What is the correct method? I would also like to bind the selected value (no multiselect) to another property from my code. Can anyone help? Not sure why I'm getting so confused.
If you are setting DataContext, you have to set the ItemsSource property to bind data.
<ListBox x:Name="listBox1" DataContext="{StaticResource BusinessData}" ItemsSource="{Binding}" SelectedValuePath="ID" DisplayMemberPath="Value" />
Otherwise, you can bind the ItemsSource directly as follows:
<ListBox x:Name="listBox1" ItemsSource="{Binding Source={StaticResource BusinessData}}" SelectedValuePath="ID" DisplayMemberPath="Value" />
You are missing the binding for ItemsSource.
Something like this:
<ListBox Name="listBox1" DataContext="{StaticResource BusinessData}" ItemsSource="{Binding myCollection}" SelectedValuePath="ID" DisplayMemberPath="Value"/>
Where myCollection is a property that exposes your list.

Categories

Resources