How to get property from the DataTemplate's parent ViewModel class - c#

I am using MVVVM Light, so I set the DataContext of the Page to the Locator. Then I set the Pivot's ItemSource to a collection property inside "myFirstVM" ViewModel class. But how to set the text of the header of the PivotItem which is in a dataTemplate of TextBox to "MyProperty" which is also defined in "myFirstVM" class?
I look at this example, but cannot figure it out:
How to access Parent's DataContext in Window 8 store apps
Here is my code:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:myApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ViewModel="using:myApp.ViewModel"
x:Class="myApp.MyTripsPage"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator}}">
<Grid x:Name="LayoutRoot">
<Pivot Name="myPivot"
Tag="{Binding}"
ItemsSource="{Binding myFirstVM.DataSource}"
ItemTemplate="{Binding myFirstVM.ViewDataTemplate}">
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyProperty, ElementName=myPivot}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
</Pivot>
</Grid>

using ElementName in a binding will bind to the element itself (Pivot in this case), whereas you want to bind to something in the DataContext of Pivot, so just add DataContext to your path:
<TextBlock Text="{Binding DataContext.myFirstVM.MyProperty, ElementName=myPivot}"/>

Related

Im creating ViewModels from MainViewModel, how can i connect View to my ViewModel [duplicate]

When I define a DataTemplate inline, Visual Studio knows about the type I'm binding to, and properties in that type come up in autocomplete (for example in the code below I was able to select DisplayName from the autocomplete list inside the FirstViewModel template).
<DataTemplate DataType="{x:Type viewmodels:FirstViewModel}">
<StackPanel >
<Label Content="{Binding DisplayName}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:SecondViewModel}">
<views:SecondView/>
</DataTemplate>
However, when the data template references an external control, as for SecondViewModel in the code above, when I'm in the file for the SecondView usercontrol, since it's just a control, the type isn't bound and the editor doesn't help me with anything.
I've tried wrapping my whole control (inside the UserControl element) in the same DataTemplate tag, but then my whole view just shows "System.Windows.DataTemplate".
<UserControl x:Class="Gui.Views.Tabs.ExamsTabViews.ExamInfoView"
xmlns:vm="clr-namespace:Gui.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<DataTemplate DataType="vm:ExamInfoViewModel">
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<!-- contents of the template -->
</DockPanel>
</DataTemplate>
</UserControl>
Is there a way to achieve this kind of binding for the editor?
<DataTemplate DataType="{x:Type viewmodels:SecondViewModel}">
<views:SecondView/>
</DataTemplate>
when this DataTemplate is instantiated, there will be created SecondView and that SecondView will have a SecondViewModel in DataContext. So there is no need any DataTemplate in SecondViewModel control - bind to DataContext instead ({Binding SecondViewModelProperty}). To have design-time support for such binding use d:DataContext="{d:DesignInstance}:
<UserControl d:DataContext="{d:DesignInstance Type=vm:ExamInfoViewModel,
IsDesignTimeCreatable=True}" ...>

Multiple DataContext bindings in UWP Page and CommandBar

I need to bind some specific elements in my UWP page to a different VIewModel than what the page has.
So in my page I bind to one DataContext:
<Page
DataContext="{Binding RootViewModel, Source={StaticResource Locator}}">
...
and I am now trying to bind the bottomAppBar CommandBar to a different ViewModel:
<Page.BottomAppBar>
<CommandBar DataContext="{Binding OtherViewModel, Source={StaticResource Locator}}">
<CommandBar.Content>
<TextBlock Text="{Binding Status}"></TextBlock>
But it doesn't work, the binding does not occur in the CommandBar.
Why?
By design, the DataContext of the CommandBar doesn't get passed to its Content. Actually, only the DataContext property of a child element will automatically get the same DataContext of its parent, unless you specifically break the flow by assigning another value to it.
In your case, the DataContext of your CommandBar will be OtherViewModel, but the Content property will remain null.
So instead of manually setting the DataContext, you should set its Content instead.
<CommandBar Content="{Binding OtherViewModel, Source={StaticResource Locator}}">
<CommandBar.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Status}"></TextBlock>
</DataTemplate>
</CommandBar.ContentTemplate>
...
</CommandBar>

Master Detail MVVM with Prism and XAML binding view in data context

I have the following dummy application where I'm trying to build a Master Detail with two views. The first is the collection view, which I can successfully select an element of and it displays in the Content Presenter Data Template with the TextBlock and TextBox defined as they are below.
I have tried to Move the TextBlock and TextBox out to a view, but have been unsuccessful at getting it to display the data. If I remove the TBs and uncomment the view, it will display the view but the TBs in the view won't populate.
Of course, the idea is that I will have more than one type.
MainWindow
<Window x:Class="MyApp.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:MyApp.Views"
mc:Ignorable="d"
xmlns:prism="http://prismlibrary.com/"
xmlns:viewModel="clr-namespace:MyApp.ViewModels"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="LayoutRoot">
<StackPanel Orientation="Horizontal">
<views:CollectionView DataContext="{Binding myItemCollection}">
</views:CollectionView>
<ContentPresenter x:Name="Detail" Content="{Binding myItemCollection.SelectedViewModel}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type viewModel:TextViewModel}">
<StackPanel>
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBox Text="{Binding Text}"></TextBox>
<!--<views:TextView/>-->
</StackPanel>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</StackPanel>
</Grid>
TextView
<UserControl x:Class="MyApp.Views.TextView"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyApp.Views"
xmlns:viewModel="clr-namespace:MyApp.ViewModels"
mc:Ignorable="d"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel>
<TextBlock Text="Text Item"/>
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBox Text="{Binding Text}"></TextBox>
</StackPanel>
</Grid>
You need to remove the prism:ViewModelLocator.AutoWireViewModel="True" attribute from your TextView.
What it does is it pulls the appropriate view model from the container and assigns the view model to TextView.DataContext. On the other hand in your template you do not explicitly pass the templated data to the TextView control, so it's expected to be inherited via automatic inheritance of DataContext. But that does not work, because TextView.DataContext is explicitly set by prism:ViewModelLocator.AutoWireViewModel="True".
In case it is required to use view model auto wiring you can always set this attribute from referencing scope, that is in XAML in which your view is "used", e.g.:
<StackPanel>
<views:TextView prism:ViewModelLocator.AutoWireViewModel="True" />
</StackPanel>

DelegateCommand inside Listview with UserControl

Is there any method to use my DelegateCommand inside my ListView with UserControl:
UserControl:
<UserControl
x:Class="App13.UserControls.ItemTemplateControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App13"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=True}"
mc:Ignorable="d">
<Grid>
<Button Content="Click" Command="{Binding OpenCommand"/>
</Grid>
</UserControl>
There is no error in my MainViewModel. There is error in Binding.
I can easily use OpenCommand in MainPage xaml using this code:
d:DataContext="{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=True}"
<Button Content="Click" Command="{Binding OpenCommand"/>
How can I bind OpenCommnad to my UserControl?
Sorry for my English and thanks in advance!
This is my ListView:
<ListView x:Name="peopleListBox">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<UserControls:ItemTemplateControl/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In the construction of your UserControl do
this.DataContext = new MainViewModel();
d:DataContext is just the Design time DataContext setting which is not applied at runtime.
By the name of it, DesignInstance is meant for design-time and not run-time.
In MVVM there are two approches of setting your ViewModel.
ViewFirst or ViewModelFirst - depending wether you build your app top down or bottom up.
for ViewFirst You can set your DataContext from your xaml :
<UserControl
x:Class="App13.UserControls.ItemTemplateControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App13"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.DataContext>
<local:MainViewModel/>
</UserControl.DataContext>
<!-- Rest of your implementation ... -->
</UserControl>
For ViewModelFirst, set it in your code behind (usually done from View's constructor)
this.DataContext = new MainViewModel();
If you want to bind a property from your viewModel to an Item in your ListBox, bind your button inside the UserControl as follows:
<Button Content="Click"
Command="{Binding DataContext.OpenCommand,
RelativeSource={RelativeSource AncestorType={x:Type ListView}}}"
/>
Hope this helps

wpf - can't use custom control

I have a custom control inside a StackPanel
<Window x:Class="Video_Editor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:m="clr-namespace:Video_Editor">
<Grid>
</StackPanel>
<ScrollViewer Margin="10,40,10,10" Grid.Row="2" VerticalScrollBarVisibility="Auto">
<StackPanel Name="stackPanel" >
<m:CustomControl Name="testControl"/>
</StackPanel>
</ScrollViewer>
</Grid>
The custom control currently doesn't do anything.
public class CustomControl: ItemsControl
{
}
I tried to do this in the window's constructor:
public MainWindow()
{
InitializeComponent();
testControl.Items.Add("item");
}
I am getting an error "the name "testControl does not exist in the current context.
You will have to use x:Name since you are deriving from another FrameworkElement that is exposing the Name property itself.
If a FrameworkElement has set its Name property (which ItemsControl seems to be doing) you cannot declare the Name property on the derived type, but you can use the Xaml x:Name property so you can decare a Name and access from code behind
Example:
<StackPanel Name="stackPanel" >
<m:CustomControl x:Name="testControl"/>
</StackPanel>

Categories