I have an ItemsControl that uses a DataTemplate which is located in an external ResourceDictionary.xaml:
<ResourceDictionary ... >
<DataTemplate x:Key="My_UserControl">
<local:MyUserControl/>
</DataTemplate>
MyUserControl.xaml file:
<UserControl ...>
<Button Content="{Binding Path=Test, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
<UserControl/>`
MainWindow.xaml uses that template in an ItemsControl.
The binding to the Window in UserControl doesn't work.
How do I bind from an external file like this UserControl to any parent, using RelativeSource so it works ?
Thanks
Try
<Button Content="{Binding Path=DataContext.Test, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
Related
I have an ItemsControl whose for the ItemTemplate DataTemplate contains a Button. I want the Command on the button to bind to a Command on the DataContext of the ItemsControl, not the ItemTemplate. I think the solution has to do with using RelativeSource, but my attempts so far have failed:
<ItemsControl ItemsSource="{Binding Games}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Path=GameSelectedCommand, Source={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding}"
Style="{StaticResource MenuButtonStyle}"
Content="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
How can I get the Button to bind to the GameSelectedCommand of the ItemsControl's DataContext object?
You're setting the source of the binding to the ItemsControl itself. Therefore, you'll need to dereference the DataContext of the ItemsControl:
Command="{Binding DataContext.GameSelectedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
How would you have known this? Take a look at your debug output window when running the app. You'll see a message along the lines of "Cannot resolve property 'GameSelectedCommand' on type 'ItemsControl'".
I have a ContextMenu in a ResourceDictionary. The ContextMenu should hide or show depending on the value of a view-model property, but it does not work.
This is my XAML code (ControlBase derives from UserControl):
<control1:ControlBase>
<UserControl.Resources>
<ResourceDictionary>
<HierarchicalDataTemplate ItemsSource="{Binding InfraNetworkItems}">
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}}">
<MenuItem Header="Delete"
Visibility="{Binding
DataContext.MyViewModel.DeleteEnabled,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=control1:ControlBase},
Converter={StaticResource
BooleanVisibilityConverter}}" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</HierarchicalDataTemplate>
</ResourceDictionary>
</UserControl.Resources>
</control1:ControlBase>
DeleteEnabled is a bool property on the view-model.
My previous attempts of solving the problem are based on this assumptions:
The ContextMenu is inside a HierarchicalDataTemplate which has the ItemsSource set. My property is not a member of this ItemSource, it belongs to the view-model. Therefore I've tried this line of code, but without any effect:
Visibility="{Binding DataContext.MyViewModel.DeleteEnabled,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=control1:ControlBase},
Converter={StaticResource BooleanVisibilityConverter}}"
But if I copy the DeleteEnabled property from the view-model to the ItemSource object, it works:
Visibility="{Binding DeleteEnabled, Converter={StaticResource BooleanVisibilityConverter}}"
what is the DataContext of your view? If it's an instance of MyViewModel you have to change the path of your Binding.
Please try this one:
<Visibility="{Binding DataContext.DeleteEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=control1:ControlBase}, Converter={StaticResource BooleanVisibilityConverter}}" />
With setting the path to DataContext you already have access to your viewmodel and of course to the DeleteEnabled-Property.
Hope this helps.
I'm using WPF to make a custom control, I need to retrieve a property that is defined in the user control code behind, so I used the RelativeSource, but I get this error
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=LeftColumnHeader; DataItem=null; target element is 'ExtDataGridComboBoxColumn' (HashCode=47761); target property is 'Header' (type 'Object')
My XAML code (the nested tree) is:
<UserControl x:Class="Administration.Views.UserRoleView"
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:WPFCtrlDg="clr-namespace:WPFControls.DataGrids;assembly=WPFControls"
xmlns:WPFCtrl="clr-namespace:WPFControls;assembly=WPFControls"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<CollectionViewSource x:Key="AllItemsView" Source="{Binding Path='AllitemsList'}" />
</UserControl.Resources>
<Grid>
<GroupBox Grid.Row="0" Grid.Column="0" Header="Assigned Elements">
<WPFCtrlDg:SelfBindingDataGrid x:Name="_sbgAssigned" ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Path=Assigned}"
SelectedItem="{Binding Path=CurrentAssignedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<WPFCtrlDg:SelfBindingDataGrid.Columns>
<WPFCtrlDg:ExtDataGridComboBoxColumn Header="{Binding Path=LeftColumnHeader,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}},
Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}"
Width="*"/>
Inside the codebehid of the usercontrol I defined my property
private string _leftColumnHeader = "TEST";
public string LeftColumnHeader
{
get { return _leftColumnHeader; }
set { _leftColumnHeader = value; }
}
}
Any idea of how to retrieve my property in order to use it as head function of my satagrid column?
thank you
Andrea
Use either
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserRoleView}},
Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Or add this to your UserControl:
<UserControl
Name="myControl"
...
Then instead of using RelativeSource use binding like this:
Header={Binding Path=LeftColumnHeader, ElementName=myControl}
But actually I'm not quite sure that you still will be able to bind it that way you do it, as columns headers have some weird rules when it comes to binding. Check it:
stackoverflow.com
stackoverflow.com
You need to use the name/type of your class, not the UserControl class that you are extending. Try this:
<WPFCtrlDg:ExtDataGridComboBoxColumn Header="{Binding Path=LeftColumnHeader,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type
UserRowView}}, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
After many searches here and also in tutorials i came up empty handed and would very appreciate help:
I have a UserControl that contains a list of other kind of UserControls.
I want to display this UserControl inside a regular WPF window:
This is the UserControl that contains the list of UserControls:
<UserControl x:Class="UsersInfo.InfoLinesContainer"...
...
<Grid>
<ListView ItemsSource="{Binding Path=InfoLineUC_ObservableList,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
</ListView>
</Grid>
And in my main window i do:
<Window x:Class="UsersInfo.MainAppWindow"
...
xmlns:usrCtr ="clr-namespace:UsersInfo"
...
<usrCtr:InfoLinesContainer Grid.Row="11"
DataContext="{Binding Path=TheInfoLines, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
ScrollViewer.CanContentScroll="True" Margin="2" Grid.ColumnSpan="7" Grid.RowSpan="6" />
...
TheInfoLines is the instance of the UserControl that contains the list of other UserControls
When i run the program the window comes up without the UserControl inside it(all i get is an empty square)
How can i make it work?
In your main window :
<usrCtr:InfoLinesContainer DataContext="{Binding Path=TheInfoLines, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />
What are you trying to bind here ? There seems to be no ancestor of type UserControl in your window.
I'm trying to bind the SelectedItem to a View. But the view is not able to access the viewmodel when it is inside the Resources block.
When the datacontext is re-assigned to the children, the binding works for textblocks but not for UserControl (NoteView)
Am I missing any Binding?
PFB revised(entire) code and inline comments.
<UserControl x:Class="Konduva.View.NoteSearchView"
<!-- other namespaces here -->
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding NoteSearch, Source={StaticResource Locator}}">
<Grid>
<ListView ItemsSource="{Binding Notes}"
SelectedItem="{Binding SelectedNote}">
<ListView.Resources>
<DataTemplate DataType="{x:Type vm:NoteViewModel}">
<DockPanel>
<TextBlock Text="{Binding Title}" />
<Popup Placement="Right"
PlacementTarget="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
IsOpen="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}">
<StackPanel>
<!-- This is working --> <TextBlock Text="{Binding SelectedNote.Title}" />
<!-- This is not working --> <v:NoteView DataContext="{Binding SelectedNote}" />
</StackPanel>
</Popup>
</DockPanel>
</DataTemplate>
</ListView.Resources>
</ListView>
</Grid>
</UserControl>
NoteView:
<Grid>
<TextBlock Text="{Binding Title}" /> // This Text is not displayed
</Grid>
Update 3
Since you're using MvvmLight: in NoteView, try changing
DataContext="{Binding Note, Source={StaticResource Locator}}"
to
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="DataContext" Value="{Binding Note, Source={StaticResource Locator}}"/>
</Style>
</UserControl.Style>
Update 2
Encountered a similar problem a few minutes ago which I didn't fully understand so I'll throw in the same solution here to see if it helps. What happends if you change it to this?
<v:NoteView DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Popup}},
Path=DataContext.SelectedNote}"/>
Update
I'm unable to reproduce this. Try adding this in your NoteView constructor. Do you reach DataContextChangedHandler when you change the selection in the ListView?
public NoteView()
{
InitializeComponent();
DependencyPropertyDescriptor dpd =
DependencyPropertyDescriptor.FromProperty(UserControl.DataContextProperty,
typeof(UserControl));
if (dpd != null)
{
dpd.AddValueChanged(this, new EventHandler(DataContextChangedHandler));
}
}
void DataContextChangedHandler(object sender, EventArgs e)
{
MessageBox.Show("DataContext Changed: " + DataContext);
}
First answer
Your DockPanel will get the NoteViewModel as a DataContext and not the ListView and since this DataContext is inherited by all Childs every child will end up with a NoteViewModel as DataContext. To use the ListView as a DataContext for the Popup you can do this. I'm not sure what the DataContext Binding for the StackPanel does though, so I might be missing something here..
<DataTemplate DataType="{x:Type vm:NoteViewModel}">
<DockPanel>
<TextBlock Text="{Binding Title}" />
<Popup Placement="Right"
PlacementTarget="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
IsOpen="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}">
<StackPanel>
<TextBlock Text="{Binding SelectedNote.Title}" />
<StackPanel>
<v:NoteView DataContext="{Binding SelectedNote}"/>
</StackPanel>
</StackPanel>
</Popup>
</DockPanel>
</DataTemplate>
Instead of inserting a NoteView directly and binding the DataContext, use a ContentPresenter:
<ContentPresenter Content="{Binding SelectedNote}>
<ContentPresenter.ContentTemplate>
<DataTemplate>
<v:NoteView />
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>