I'm just not getting it: I've a ribbon-menu where some tabs/groups/buttons are defined in xaml and some tabs/groups/buttons are defined during runtime (user loads a certain "command set"). To realise this I put the ribbonTab which is defined in xaml and a collection container inside a compositeCollection.
MainWindow.xaml
<RibbonWindow x:Class="test_ribbonButtonBinding.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:local="clr-namespace:test_ribbonButtonBinding"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" DataContext=" {StaticResource svm}">
<RibbonWindow.Resources>
<CollectionViewSource x:Key="tabs" Source="{Binding ribbon}"/>
</RibbonWindow.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Ribbon x:Name="RibbonMenu" Grid.Column="0" Grid.Row="0">
<Ribbon.ItemsSource>
<CompositeCollection>
<RibbonTab Header="Testtab" >
<RibbonGroup x:Name="Testgroup" Header="Testgroup">
<RibbonButton LargeImageSource="Icons/question.png" Label="TestAddCommand" Command="{Binding cmdTestAddCommand}" />
<RibbonButton LargeImageSource="Icons/question.png" Label="TestReadCommand" Command="{Binding cmdTestReadCommand}" CommandParameter="{Binding SelectedItem, ElementName=lstSequence}"/>
</RibbonGroup>
</RibbonTab>
<CollectionContainer Collection="{Binding Source={StaticResource tabs}}"/>
</CompositeCollection>
</Ribbon.ItemsSource>
</Ribbon>
<ListView x:Name="lstSequence" ItemsSource="{Binding sequence}" Grid.Row="1" Grid.Column="0" SelectionMode="Extended"/>
</Grid>
</RibbonWindow>
Problem now arises for the CommandParameter of the already defined buttons:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=lstSequence'. BindingExpression:Path=SelectedItem; DataItem=null; target element is 'RibbonButton' (Name=''); target property is 'CommandParameter' (type 'Object')
This might be simple but I just can't wrap my head around it: how do I bind the commandparameter to the selectedItems in the ListView. It's obviously the wrong dataContext.
What further confuses me: if I leave out the composite collection (so all tabs are just defined inside the xaml) the command binds correctly to the element inside the viewmodel and the commandparameter binds correctly to the elements in the window (how does this work anyway, should BOTH bind to the viewmodel as it is specified in the DataContext of the window???)
Any help appreciated.
Resu
EDIT:
Finally setting a setter property in the listview solved the problem
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
But I'm still wondering why my method doesn't work anypody else an explanaition for this?
Two options (untested):
1) use parent element to pass value via RelativeSource:
<Grid Tag={Binding SelectedItem, ElementName=lstSequence}>
...
<!-- hopefully there are no other grids on the way -->
<RibbonButton CommandParameter="{Binding Tag, RelativeSource={RelativewSource FindAncestor, AncestorType=Grid}}"
Command="{Binding cmdTestReadCommand}" .../>
...
<ListView x:Name="lstSequence" ... />
</Grid>
2) do not use parameter at all
<ListView SelectedItem={Binding SelectedItem, Mode=OneWayToSource} ... />
view model:
public whatevertype SelectedItem { get; set; }
inside command execute delegate
var parameter = SelectedItem;
Related
I have a HeaderedContentControl in my application. In this HeaderedContentControl there is a TabControl.
Now I want to display the name of the selected tab (TabItem) in the header of the HeaderedContentControl (like in Visual Studio the Solution Explorer / Team Explorer e.g.).
My application is (partly) based on Josh Smiths WPF-MVVM-Example but I use additional Prism with Unity.
Furthermore I split the resources in some files.
Here is my MainView.xaml:
<UserControl x:Class="STController.ModuleAComport.View.MainView"
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"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="..\Resources\MainViewResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.Resources>
</Grid.Resources>
<Border Grid.Row="0"
Grid.Column="0"
Style="{StaticResource MainBorderStyle}">
<HeaderedContentControl Header="?"
Style="{StaticResource MainHeadreredContentControlStyle}"
ContentTemplate="{StaticResource WorkspacesTemplate}"
Content="{Binding Path=Workspaces}" />
</Border>
</Grid>
</UserControl>
And here is my MainViewResources.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:STController.ModuleAComport.View"
xmlns:viewmodel="clr-namespace:STController.ModuleAComport.ViewModel">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/STController.Resources;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Put your not shared resource here -->
<DataTemplate DataType="{x:Type viewmodel:ComportViewModel}">
<view:ComportView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:TestViewModel}">
<view:TestView />
</DataTemplate>
<DataTemplate x:Key="TabItemTemplate">
<Grid>
<ContentPresenter VerticalAlignment="Center"
Content="{Binding Path=DisplayName}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl x:Name="TabControl"
IsSynchronizedWithCurrentItem="True"
TabStripPlacement="Bottom"
Style="{StaticResource MainTabControlStyle}"
ItemsSource="{Binding}"
Margin="4"
ItemTemplate="{StaticResource TabItemTemplate}"
ItemContainerStyle="{StaticResource MainTabItemStyle}">
</TabControl>
</DataTemplate>
</ResourceDictionary>
I had two different solution approaches:
1) Binding the SelectedIndex:
My first idea was to bind the SelectedIndex of the TabControl to a property in my viewmodel.
With the index I can then "select" the related view (viewmodel) and get the name and bind it to the header (see HeaderedContentControl; Content="{Binding Path=Workspaces}"; Workspaces is of type ObservableCollection)
But once I bind the SelectedIndex property of the TabControl, the TabControl does not switch reliable anymore. Sometimes when I click on the TabItem it is switching sometimes not. Sometimes I need to click ten or more times. A very strange behavior. There is no difference if I implement the property (SelectedIndex) in my viewmodel or not.
2) Elementbinding:
My second idea was to implement a ElementName-Binding
But as I expected this does not work (Visual / Logical Tree). The error is:
"Cannot find source for binding with reference 'ElementName=TabControl'.
BindingExpression:Path=ActualHeight; DataItem=null; target element is
'HeaderedContentControl' (Name=''); target property is 'Header' (type
'Object')"
In this case I also tried to move the TabControl into the Resources of the UserControl and Grid.
So the question is: Is it possible / how is it possible to show the name of the selected tab of the TabControl in the header of the HeaderedContentControl?
Is there a solution without code behind (I don't really like code behind ;) )?
I have a TreeView object bound to a DataSet. Inside of the TreeView.ItemTemplate, I am using a HierarchicalDataTemplate containing the controls that I am rendering.
Does anyone know how to change the Visibility property of a control inside of a HierarchicalDataTemplate? I have tried using the BooleanToVisibilityConverter from the .NET framework, but cannot get the binding to work properly.
The boolean variable in my ViewModel named "moveButtonVisibility" is bound to the Visibility property of the button in my XAML. The BooleanToVisibilityConverter then attempts to convert the corresponding boolean value (true/false) to a Visibility value (visible/hidden). "moveButtonVisibility" is not part of the TreeView's ItemSource.
A stripped down version of my code is shown below. I have removed all of the code in my XAML except for the Button control "MoveHereButton" that I want to change the visibility property on:
VIEWMODEL (C#):
private bool _moveButtonVisibility;
public bool moveButtonVisibility
{
get { return _moveButtonVisibility; }
set
{
_moveButtonVisibility = value;
RaiseChange("moveButtonVisibility");
}
}
VIEW (XAML):
<Page>
<Page.Resources>
<BooleanToVisibilityConverter x:Key="visibilityConverter"/>
</Page.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Top">
<TreeView HorizontalAlignment="Center" x:Name="treeView1" VerticalAlignment="Top" ItemsSource="{Binding Path=rsParentChild}" Background="Transparent" BorderThickness="0" BorderBrush="Transparent" >
<TreeView.ItemContainerStyle>
<Style>
<Setter Property="TreeViewItem.IsExpanded" Value="True"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=rsParentChild, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<Grid Focusable="False" Margin="5,10,5,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Name="MoveHereButton" Content="Move Here" Visibility="{Binding DataContext.moveButtonVisibility, Converter={StaticResource visibilityConverter}}" Click="MoveHereButton_Click" />
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Page>
The following worked:
<Button Name="MoveHereButton"
Content="Move Here"
Visibility="{Binding DataContext.moveButtonVisibility,
RelativeSource={RelativeSource AncestorType={x:Type Page}},
Converter={StaticResource visibilityConverter}}"
Click="MoveHereButton_Click" />
The key was to add:
RelativeSource={RelativeSource AncestorType={x:Type Page}}
inside of the Visibility binding to force the control to use the DataContext of the Page.
I have a Problem with the ComboBox at wpf and xaml. The ItemsSource of my combobox is a list of (CollarTypesImage).
the binding is work fine but the problem when editing data, i can't select the item of my ComboBox.. maybe its selected but the image is not view...
but when click ComboBox, i can see all itams:
http://www.ahmadabouhamdh.com/tmp_global/1.png
i used RelativeSource , nothing changed, ComboBox not selection the my saved item:
<UserControl x:Class="TailorManager.Views.OrderDetailItem"
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:vm="clr-namespace:TailorManager.ViewModels"
xmlns:Converter="clr-namespace:TailorManager.Converters"
mc:Ignorable="d"
d:DesignHeight="730" d:DesignWidth="556" FlowDirection="RightToLeft" >
<UserControl.Resources>
<!--<vm:OrderDetailItemViewModel x:Key="OrderDetailItemViewModel1" />-->
<Converter:ImageConverter x:Key="ImgConverter" />
</UserControl.Resources>
<Grid >
<ScrollViewer VerticalScrollBarVisibility="Auto" >
<ItemsControl>
<StackPanel>
<GroupBox Header="تفاصيل الياقة" Margin="5,5,5,0" VerticalAlignment="Top" Height="170">
<Grid>
<ComboBox ItemsSource="{Binding Path= DataContext.ImagesCollarTypes,
RelativeSource={RelativeSource AncestorType=UserControl,AncestorLevel=1}}"
SelectedValue="{Binding Path=OrderDetailItem.CollarTypesImage,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="{Binding Path=OrderDetailItem.CollarTypesImage}"
Margin="393,106,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="132" Height="38">
<ComboBox.ItemTemplate>
<DataTemplate>
<Image Width="50" Height="50" Source="{Binding Path= CollarImage,Converter={StaticResource ImgConverter} }" />
</DataTemplate>
</ComboBox.ItemTemplate >
</ComboBox>
</Grid>
</GroupBox>
<Grid/>
</StackPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
</UserControl>
i added
SelectedItem="{Binding Path=OrderDetailItem.CollarTypesImage}"
and nothing changed.
i use this Control inside window has a different DataContext type,i set the value of (DataContext OrderDetailItem) from constructor of this control.
image below explain the binding is working fine:
this image when click edit to show my saved image from DB, my item not selected:
http://www.ahmadabouhamdh.com/tmp_global/2.png
here all the code:
public List<CollarTypesImage> ImagesCollarTypes
{
get
{
//ImagesCollarTypes[0].CollarImage
if (_imagesCollarTypes.Count == 0)
{
TailorManagerDBEntities db = new TailorManagerDBEntities();
_imagesCollarTypes = db.CollarTypesImages.ToList();
}
return _imagesCollarTypes;
}
set
{
_imagesCollarTypes = value;
RaisePropertyChanged(() => ImagesCollarTypes);
}
}
public partial class CollarTypesImage
{
public CollarTypesImage()
{
this.OrderDetails = new HashSet<OrderDetail>();
}
public System.Guid CollarTypeId { get; set; }
public byte[] CollarImage { get; set; }
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
}
here the xaml code from window i used my control:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:TailorManager.ViewModels"
xmlns:util="clr-namespace:TailorManagerLib.Business;assembly=TailorManagerLib"
xmlns:local="clr-namespace:TailorManager.Views"
x:Class="TailorManager.Views.AddOrder"
Title="AddCustomer" Height="665" Width="974" MinWidth="600" MinHeight="666" FlowDirection="RightToLeft" >
<Window.Resources>
<vm:ManageOrderDetilsViewModel x:Key="ManageOrderDetilsViewModel1" />
</Window.Resources>
<Grid DataContext="{StaticResource ManageOrderDetilsViewModel1}" x:Name="GridDataContaner">
<Grid.Background>
...
</Grid.Background>
<GroupBox Header="تفاصيل الطلب" Margin="10,160,10,0" FlowDirection="RightToLeft">
<Grid Grid.Column="0" Name="GridOrderDetails">
<Grid.ColumnDefinitions>
<ColumnDefinition Name="ColumnDefinitionListDetails" Width="183*"/>
<ColumnDefinition Name="ColumnDefinitionDetails" Width="0*"/>
</Grid.ColumnDefinitions>
<Grid Margin="0,0,0,40" >
...
</Grid>
<Grid Grid.Column="1">
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="3" Margin="4" >
<Grid>
<local:OrderDetailItem x:Name="OrderDetailItemControl" VerticalAlignment="Top" />
</Grid>
</Border>
</Grid>
...
</Grid>
</GroupBox>
</Grid>
</Window>
how i set the DataContext of the Control, this inside the command in VM of my window:
OrderDetailItemViewModel OrdDetailItem = new OrderDetailItemViewModel(Ord.OrderDetailsId);
OrderDetailItemControl.DataContext = OrdDetailItem;
Please how to fix it??
UPDATE
when i change the relative source as below:
<ComboBox Name="CmbBxImgCollarTyp" ItemsSource="{Binding Path= DataContext.ImagesCollarTypes, RelativeSource={
RelativeSource AncestorType={x:Type vm:OrderDetailItemViewModel}}"
SelectedValue="{Binding Path=OrderDetailItem.CollarTypesImage, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="{Binding Path= OrderDetailItem.CollarTypesImage}" Margin="393,106,0,0" VerticalAlignment="Top"
HorizontalAlignment="Left" Width="132" Height="38">
<ComboBox.ItemTemplate>
<DataTemplate>
<Image Width="50" Height="50" Source="{Binding Path=CollarImage,
Converter={StaticResource ImgConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
the binding never work at all modes!, i change it to this way cause the datacontext of this control is an object of the viewmodel "OrderDetailItemViewModel"
What should be fix؟؟
You have an error in your RelativeSource Binding Path. You have used the type of UserControl, but the UserControl class does not have a property named ImagesCollarTypes... instead, you should use your UserControl where you defined the property... I'm assuming that class was named OrderDetailItem:
<ComboBox ItemsSource="{Binding Path= DataContext.ImagesCollarTypes, RelativeSource={
RelativeSource AncestorType={x:Type YourViewsPrefix:OrderDetailItem}}}"
SelectedValue="{Binding Path=CollarTypesImage, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="{Binding Path=
CollarTypesImage}" Margin="393,106,0,0" VerticalAlignment="Top"
HorizontalAlignment="Left" Width="132" Height="38">
<ComboBox.ItemTemplate>
<DataTemplate>
<Image Width="50" Height="50" Source="{Binding Path=CollarImage,
Converter={StaticResource ImgConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You should have received an error in the Output Window in Visual Studio saying something like Error: property 'ImagesCollarTypes' not found on object 'UserControl' or something similar.
Disclaimer: I didn't go through all of your code because you simply have too much there, so even after you fix this error, your code may still have other errors and not work as expected.
UPDATE >>>
For this Binding to work, the following assumptions were made:
The UserControl.DataContext must have a valid instance of an object set.
The object set as the UserControl.DataContext must have a public property named ImagesCollarTypes.
The ImagesCollarTypes property must be of a type that contains a public property named CollarTypesImage.
after check the Output window, i notes this error:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'RelativeSource FindAncestor, AncestorType='Projectname.ViewModels.ViewModel', AncestorLevel='1''. BindingExpression:Path=LookupItems; DataItem=null; target element is 'ComboBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
then i change the RelativeSource from AncestorType from my ViewModel to UserControl, just like this:
RelativeSource={ AncestorType={x:Type UserControl},AncestorLevel=1}}"
and now everything working fine,
Thanks for members make an effort
In my application I have a two TreeView objects that are bound to the same data.
I made a user control for the Tree which is called TreeView and looks like this:
<UserControl x:Class="MyApp.Views.TreeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:MyApp.Model"
xmlns:viewModel="clr-namespace:MyApp.ViewModels"
xmlns:views="clr-namespace:MyApp.Views"
xmlns:converters="clr-namespace:MyApp.Converters">
<UserControl.Resources>
<converters:EnumToPicConverter x:Key="Converter"></converters:EnumToPicConverter>
<!--Control colors.-->
<Style x:Key="MyTreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=(model:TreeNode.IsExpanded), Mode=TwoWay}" />
</Style>
<HierarchicalDataTemplate DataType="{x:Type model:TreeNode}" ItemsSource="{Binding ChildListNodes}">
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEqual}" Value="false">
<Setter Property="TreeViewItem.Background" Value="Blue"></Setter>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=EntityType,Converter={StaticResource Converter}}" />
<TextBlock Margin="5,0" Text="{Binding ItemName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/>
</StackPanel>
</HierarchicalDataTemplate>
</UserControl.Resources>
<TreeView ItemsSource="{Binding RootNode}" ItemContainerStyle="{StaticResource MyTreeViewItemStyle}" />
Now, In my main window, I use it in the following way:
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:MyApp.Model"
xmlns:viewModel="clr-namespace:MyApp.ViewModels"
xmlns:views="clr-namespace:MyApp.Views"
xmlns:converters="clr-namespace:MyApp.Converters"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<viewModel:TreeViewModel/>
</Window.DataContext>
<DockPanel>
<Grid DockPanel.Dock="Top" Name="LoadRow">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<views:DbChooser Path="{Binding Path1}" ReloadCommand="{Binding LoadFileACommand}" Grid.Column="0"/>
<views:DbChooser Path="{Binding Path2}" ReloadCommand="{Binding LoadFileBCommand}" Grid.Column="1"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<views:TreeControl Grid.Column="0" ItemName="{Binding Name1}"/>
<views:TreeControl Grid.Column="1" ItemName="{Binding Name2}"/>
</Grid>
</DockPanel>
Problem is that:
The DataContext is "viewModel:TreeViewModel" , but I want to bind each treeViewItem's Textblock content to a different property of "model:TreeNode" (which is the type of class of the TreeNodeItem holds..)
And in the main window it says "Cannot resolve property "Name1" in data context of type 'MyApp.ViewModels.TreeViewModel' .
I tried various different options and read few posts here in StackOverFlow but couldn't find a solution..
Thanks for any help.
edit, few clarifications:
1. TreeControl just wraps WPF TreeView (you can see the code is pasted..)
2. The DataContext of The MainWindow is TreeViewModel, it is a class that holds the Root Node of the tree (of type TreeNode) and few other properties I use. The Property that I want to "send" to the TreeControl is a property of type TreeNode, which is the type of the TreeViewItems
Another edit:
In other words, what I want to accomplish is that:
To "tell" to the first TreeControl " Please put in the text block of each TreeNodeItem the content of the the property 'Name1' "
And to "tell" the second TreeControl "Please put in the text block of each TreeNodeItem the content of the property 'Name2' "
I do not try to answer but perhaps give you some hints to debug.
You can use "DataContextChanged" event on most xaml tag to make sure you get the DataContext you expect.
If you have the expected DataContext but got warning in xaml. You could use:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
and set:
<AnyTagThatHasDataContext d:DataContext="{d:DesignInstance Type=youDataContextObject}">
That will help to design your window/UserControl
I have a small application to help myself learn WPF and MVVM etc. I have been using the example by Josh Smith found here to construct my own application. I have got the application adding TabItems, but the embedded DataGrid which is bound to an ObservableCollection<ResourceViewModel> is not showing any data, see the image below:
The DataGrid is the section surrounded in blue. The UserControl also seems to be showing the in the tab itself for some reason, but that is not the problem I am asking about here. The UserControl contains a DataGrid which is bound as follows
<DataGrid ItemsSource="{Binding Resources}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox,
Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro"
AlternationCount="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...</DataGrid>
The Resources property is defined in the ViewModels namespace as
internal class ResourceDataViewModel : WorkspaceViewModel
{
readonly ResourceDataRepository resourceRepository;
public ObservableCollection<ResourceViewModel> Resources { get; private set; }
...
}
Where the ResourceViewmodel holds the information for each row of the DataGrid. I can confirm that the Resource property is populated. When I use the same model outside of MVVM and populate Resource in the same way it works. Can someone provide me with and idea of why this could be happening?
I have attempted to set the explicit path for the binding
ItemsSource="{Binding Path=(viewModels:Resources)}"
but this also does not work. Thanks for your time.
Edit. To address comments. I set the DataContext in the App.xaml.cs file by
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
// Create the ViewModel to which
// the main window binds.
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
// When the ViewModel asks to be closed,
// close the window.
EventHandler handler = null;
handler = delegate
{
mainWindowViewModel.RequestClose -= handler;
window.Close();
};
mainWindowViewModel.RequestClose += handler;
// Allow all controls in the window to
// bind to the ViewModel by setting the
// DataContext, which propagates down
// the element tree.
window.DataContext = mainWindowViewModel;
window.Show();
}
The XAML of the MainWindow:
<Window x:Class="ResourceStudio.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
Title="MainWindow" Height="629.4" Width="814.4">
<Window.Resources>
<ResourceDictionary Source="MainWindowResources.xaml" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="284*"/>
<ColumnDefinition Width="567*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="48"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<DockPanel KeyboardNavigation.TabNavigation="None"
Background="#FFBEC8D8"
Grid.ColumnSpan="2"
Margin="0,0,0.4,0">
<Menu DockPanel.Dock="Top"
Background="#FFF9F9F9"
BorderBrush="Black"
KeyboardNavigation.TabNavigation="Cycle">
<MenuItem Header="_File">
<MenuItem Header="Load _Resource..."
Height="Auto"
Command="{Binding LoadResourceCommand}"/>
<MenuItem Header="_Add Language..."
Height="Auto"/>
<Separator/>
<MenuItem Header="Close _Workspace"
Height="Auto"
Command="{Binding CloseCommand}"/>
<MenuItem Header="E_xit"
Height="Auto" Command="{Binding CloseCommand}" />
</MenuItem>
<MenuItem Header="_Edit">
</MenuItem>
</Menu>
<ToolBarTray DockPanel.Dock="Top" MaxHeight="24" Background="#FFF9F9F9">
<ToolBar Background="#FFF9F9F9">
<Button ToolBar.OverflowMode="Never">One</Button>
<Button>Two</Button>
<Button>Three</Button>
</ToolBar>
</ToolBarTray>
</DockPanel>
<Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="0,0,0.4,23.6" Grid.RowSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl ItemsSource="{Binding Path=Workspaces}"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
TabStripPlacement="Top"
Height="Auto"
Width="Auto">
</TabControl>
</Grid>
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" Margin="0,0.4,0.4,-0.4">
<StatusBarItem DockPanel.Dock="Left" Background="#FF007ACC" Margin="0,2,0,0">
<TextBlock Text="Ready" Margin="5,0,0,0"/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
Where the MainWindowResources.xaml is:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
The full code for the ResourceControl.xaml is:
<UserControl x:Class="ResourceStudio.Views.ResourceControl"
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:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:dataAccess="clr-namespace:ResourceStudio.DataAccess"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Name="control">
<DockPanel DataContext="{Binding ElementName=control}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBox Text="M" DockPanel.Dock="Top" Name="searchBox" />
<Grid DockPanel.Dock="Top">
<Border BorderBrush="#FF007ACC" BorderThickness="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid ItemsSource="{Binding Path=(viewModels:Resources)}"
dataAccess:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
AlternatingRowBackground="Gainsboro" AlternationCount="2" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DataGrid.Resources>
<dataAccess:SearchValueConverter x:Key="searchValueConverter"/>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="dataAccess:DataGridTextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource searchValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
<Binding RelativeSource="{RelativeSource Self}" Path="(dataAccess:DataGridTextSearch.SearchValue)" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="dataAccess:DataGridTextSearch.IsTextMatch" Value="True">
<Setter Property="Background" Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#FF007ACC"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</Border>
</Grid>
</DockPanel>
</UserControl>
The TextBox is bound to the DataGrid. When the user types into that TextBox the DataGrid filters and highlights the cells which contains the required text. This however, is not the problem and this code works, it is just the binding to the DataGrid I am interested in. Thanks again for tour time.
Edit2: According to #dkozl's comments I have removed the DataContext="{Binding ElementName=control}" from the DockPanel declaration, so we now have
<DockPanel HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
...
and in the MainWindowResource.xaml I now have
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels"
xmlns:views="clr-namespace:ResourceStudio.Views"
>
<!--This template applies a ResourceControl view to an instance of the
ResourceDataViewModel class shown in the main window.-->
<DataTemplate DataType="{x:Type viewModels:ResourceDataViewModel}">
<views:ResourceControl DataContext="{Binding}"/>
</DataTemplate>
<!--This template explains how to render the 'Workspace'
content area in the main window.-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
Margin="4"/>
</DataTemplate>
</ResourceDictionary>
This has not worked. That is my DataGrid in the ResourceControl is not being populated. Thanks again for your time it is most appreciated...
Your UserControl DockPanel.DataContext is bound to ResourceControl control and not to ResourceDataViewModel class. What you need to do instead is to bind DataContext of ResourceControl in your DataTemplate. To achive that first remove DataContext="{Binding ElementName=control}" from ResourceControl.DockPanel and then bind ResourceControl.DataContext to your object by <views:ResourceControl DataContext={Binding}"/>. Also you need to change DataGrid items binding from ItemsSource="{Binding Path=(viewModels:Resources)}" to ItemsSource="{Binding Path=Resources}".
Not part of the original question but same template applies to tab header and tab content because DataTemplate is type specific and in this case tab header content and tab content is the same thing. To solve the issue remove DataTemplate for viewModels:ResourceDataViewModel type and put this directly into your main TabControl:
<TabControl.ContentTemplate>
<DataTemplate>
<views:ResourceControl DataContext={Binding}"/>
</DataTemplate>
</TabControl.ContentTemplate>