Why is my WPF ContextMenu Item disabled? - wpf

I have a small but annoying problem with my ContextMenu in a WPF application.
I use a DataTemplate for my List of ViewModel-objects to create the visual elements. In the DataTemplate I simply set my UserControl like this:
<!-- Define a data-template for the 'RoomViewModel' class. This generates the UI for each node. -->
<DataTemplate DataType="{x:Type model:RoomViewModel}">
<network:RoomView network:ConstraintView.ArgumentChanged="ConstraintView_ArgumentChanged"></network:RoomView>
</DataTemplate>
I want the RoomView to have a ContextMenu where a RelayCommand should be executed if the user clicks on the MenuItem. My UserControl for the RoomView looks like this at the moment:
<UserControl x:Name="userControl" x:Class="NetworkUI.RoomView"
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:network="clr-namespace:NetworkUI"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" DataContextChanged="userControl_DataContextChanged">
<UserControl.Resources>
<!-- UI commands -->
<RoutedCommand x:Key="Commands.NewConstraintCmd"></RoutedCommand>
</UserControl.Resources>
<UserControl.CommandBindings>
<CommandBinding x:Name="newConst" Command="{StaticResource Commands.NewConstraintCmd}" Executed="NewConstraint_Executed"></CommandBinding>
</UserControl.CommandBindings>
<Grid Width="Auto" Height="Auto" MinWidth="50" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Width="Auto" Height="20" MinWidth="50" >
<Rectangle Stroke="Black" Fill="White" RadiusX="4" RadiusY="4" SnapsToDevicePixels="True" ></Rectangle>
<Grid Margin="-4" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" MinWidth="10" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<network:EditableTextBlock Grid.Column="1" Grid.Row="1" x:Name="nameTextBox" Text="{Binding Name, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="{x:Null}" />
<network:ConnectorItem Grid.Row="1" Grid.Column="0" DataContext="{Binding Connectors[0]}" />
<network:ConnectorItem Grid.Row="1" Grid.Column="2" DataContext="{Binding Connectors[1]}" />
</Grid>
</Grid>
<StackPanel Grid.Row="1" x:Name="roomProperties" Width="Auto" HorizontalAlignment="Stretch" >
<ItemsControl ItemsSource="{Binding PropertyGroups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<network:ConstraintCollectionView></network:ConstraintCollectionView>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
<UserControl.ContextMenu>
<ContextMenu x:Name="contextMenu">
<MenuItem Header="new Constraint" Command="{StaticResource Commands.NewConstraintCmd}"></MenuItem>
</ContextMenu>
</UserControl.ContextMenu>
</UserControl>
I am not really sure if my UserControl code is ok. In my CodeBehind file I define a
public ICommand NewConstraintCmd;
-Command that should be executed when the user clicks the Item. My Executed handler is simple and looks like this:
private void NewConstraint_Executed(object sender, ExecutedRoutedEventArgs e) {
ViewModel.AddConstraint();
}
The ViewModel is indeed a RoomViewModel and the NewConstraintCmd is set in the DataContextChanged - event (not displayed here).
My simple question is, why is my ContextMenu-Item always disabled? I mean the RelayCommand.CanExecute is never checked, is this the problem maybe?
I didn't find any solution for my problem yet.
Thank you for any help!

Thank you Rohit Vats! I changed my ICommand definition to this:
public static readonly ICommand NewConstraint = new RelayCommand((rvm) => AddConstraint(rvm));
Since this is a static method I needed the parameter (the DataContext of my RoomView).
My Method is defined like this now:
private static void AddConstraint(object rvm) {
if (rvm is RoomViewModel)
(rvm as RoomViewModel).AddConstraint();
}
So first the parameter is checked and if it is ok (a RoomViewModel object) I call the actual function on the object.
I have no idea why it works now, really :/.
My XAML code for the MenuItem now looks like this:
<MenuItem Header="new Constraint" Command="network:RoomView.NewConstraint" CommandParameter="{Binding}"></MenuItem>
As mentioned before I need the CommandParameter to call a function on it. Since the needed Object is my DataContext I just use the {Binding} to pass the object.
This really works fine now, I hope it will work with InputBindings as well in the future :)!
Thank you again for the help!

Related

WPF ComboBox bind itemssource to different datacontext in MVVM

I have a user control that has its datacontext set to a view model called EmployeeList_VM. I then have a ContentControl within that user-control that has its datacontect set to a public property (EmployeeSelection) of the view model. The ContentControl's datacontext is the same as the selected item binding of a listbox within the same user control.
I want to have a combobox (of an observblecollection called EmployeeStatus) within the ContentControl bind its selecteditem to a property of the EmployeeSelection datacontext of the ContentControl. I want the itemssource of the combobox to bind to a public property EmployeeStatus of the "parent" viewmodel EmployeeList_VM.
I can get a list of the employees status to appear wihtin the combobox. I can not get it to bind to the idStatus property of the EmployeeSelection.
Here is What I have so far (some code removed for readability):
<UserControl x:Class="FTC.View.EmployeeListView"
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:FTC_Application"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="http://www.galasoft.ch/mvvmlight"
mc:Ignorable="d"
DataContext="{Binding EmployeeList_VM, Source={StaticResource Locator}}"
d:DesignHeight="900" d:DesignWidth="1000">
<Expander x:Name="DetailExpander" Grid.Column="2" Header="employee detail" Style="{DynamicResource ExpanderStyle_FTC}" IsExpanded="True" Padding="8,0,0,10" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" >
<Button Content="" Style="{DynamicResource ButtonSave}" Command="{Binding SaveCommand}" ToolTip="Save Changes" Margin="0,0,10,10"/>
<Button Content="" Style="{DynamicResource ButtonUndo}" Command="{Binding UndoCommand}" ToolTip="Undo Changes" Margin="0,0,10,10"/>
</StackPanel>
<ScrollViewer Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentControl DataContext="{Binding Path=EmployeeSelection, Mode=TwoWay}" >
<!-- FTC SETTINGS GRID CONTENT-->
<Grid Grid.ColumnSpan="6" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="SettingsHeading" Text="FTC Settings" Style="{StaticResource FTC_DetailHeading}" Grid.ColumnSpan="5"/>
<TextBlock Text="Status" Style="{StaticResource FTC_DetailLabelSub}" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1"/>
<ComboBox Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2"
Margin="5,5,16,5" Height="37"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.EmployeeStatus}"
SelectedItem="{Binding idStatus, Mode=TwoWay}"
SelectedValuePath="idStatus"
DisplayMemberPath="chrCode" FontSize="18"/>
</Grid>
</ContentControl>
</ScrollViewer>
</Grid>
</Expander>
</UserControl>
I even tried the following change (I named the ContentControl DetailControl) for the selected item of the combobox:
SelectedItem="{Binding ElementName=DetailControl, Path=DataContext.idStatus}"
Can someone please help me get the selected item binding hooked up properly. The combobox displays all the right items, but they do not bind to the EmployeeSelection.idStatus.
Thanks in advance.
so here is what worked for me, hope it can help someone else
<ComboBox Name="cbStatus" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2"
Style="{StaticResource FTC_DetailComboBox}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.EmployeeStatus}"
SelectedItem="{Binding ElementName=DetailControl, Path=DataContext.employee_status}"
SelectedValuePath="idStatus"
SelectedValue="{Binding idStatus, Mode=TwoWay, ValidatesOnDataErrors=True}"
DisplayMemberPath="chrCode"/>

MVVM + UserControl + UserControl + DependencyProperty

I have a user control which displays addresses housed inside of another page that is bound to a viewmodel. The viewmodel has a primitive User which has a collection of Address objects. The User control will reside on several pages so I would like to be able to bind it to the address list via a dependency property. While my current solution is working, something about it just doesn't feel right and I thought I'd ask for a second opinion. I have chopped out a lot of code for brevity's sake.
Basically the page binds to the dependency property in the usercontrols code behind which then updates the usercontrol's datagrid by setting it's itemsource. This seems to me to break the basic tenants of MVVM.
AddressListView control:
<UserControl x:Class="Insight.Controls.AddressListView"
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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:tk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
xmlns:command="clr-namespace:PrismFramework.Implementors.Commanding;assembly=PrismFramework"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="840">
<UserControl.Resources>
<command:ObservableCommand x:Name="EditAddressCommand" Value="{Binding EditAddressCmd}"/>
<command:ObservableCommand x:Name="DeleteAddressCommand" Value="{Binding DeleteAddressCmd}"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid Name="dgAddresses"
Height="Auto"
Width="Auto"
AutoGenerateColumns="False"
HeadersVisibility="None" >
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn x:Name="dgcAddresses"
Width="*" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border x:Name="bdrAddress"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="Auto"
BorderBrush="Silver"
BorderThickness="1"
Padding="0"
Margin="1,1,1,1">
<Grid x:Name="grdAddressItem"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="17" MinHeight="17"/>
<RowDefinition Height="17" MinHeight="17"/>
<RowDefinition Height="17" MinHeight="17"/>
<RowDefinition Height="17" MinHeight="17"/>
<RowDefinition Height="17" MinHeight="17"/>
<RowDefinition Height="17" MinHeight="17"/>
<RowDefinition Height="17" MinHeight="17"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="55" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Padding="0,0,5,0" Text="Type:" TextAlignment="Right" />
<TextBlock Grid.Column="1" Padding="0" Text="{Binding Path=AType}" Grid.ColumnSpan="2" />
<TextBlock Grid.Row ="1" Grid.Column="0" Padding="0,0,5,0" Text="Address 1:" TextAlignment="Right" />
<!-- List Of Similar Fields ->
<Grid x:Name="grdAddressEditOptions"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="Auto"
Grid.Column="3"
Grid.RowSpan="7" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button x:Name="btnEdit"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="Auto"
Grid.Row="0"
Padding="4,5,4,8"
Margin="0,8,10,0"
Command="{Binding Value, Source={StaticResource EditAddressCommand}}"
CommandParameter="{Binding}" >
<Button.Content>
<Image x:Name="btnEditIcon"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="Auto"
Width="Auto"
Source="/Insight.ModuleUser;component/Images/edit.png"
Visibility="Visible" />
</Button.Content>
</Button>
<Button x:Name="btnDelete"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="Auto"
Grid.Row="2"
Padding="4,5,4,8"
Margin="0,0,10,5"
Command="{Binding Value, Source={StaticResource DeleteAddressCommand}}"
CommandParameter="{Binding}" >
<Button.Content>
<Image x:Name="btnDeleteIcon"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="Auto"
Width="Auto"
Source="/Insight.ModuleUser;component/Images/delete.png"
Visibility="Visible" />
</Button.Content>
</Button>
</Grid>
</Grid>
</Border>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</UserControl>
AddressListView code behind:
Imports System.Collections.ObjectModel
Imports Insight.DataServices.Primitives
Partial Public Class AddressListView
Inherits UserControl
Public ReadOnly AddressesProperty As DependencyProperty = DependencyProperty.Register("Addresses", GetType(ObservableCollection(Of Address)), GetType(AddressListView), New PropertyMetadata(Nothing, New PropertyChangedCallback(AddressOf OnAddressesChanged)))
Public Sub New()
InitializeComponent()
End Sub
Public Property Addresses As ObservableCollection(Of Address)
Get
Return DirectCast(GetValue(AddressesProperty), ObservableCollection(Of Address))
End Get
Set(value As ObservableCollection(Of Address))
SetValue(AddressesProperty, value)
End Set
End Property
Public Sub OnAddressesChanged()
Me.dgAddresses.ItemsSource = Addresses
End Sub
End Class
Base page:
<UserControl x:Class="Insight.ModuleUser.Views.EditUserView"
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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cm="clr-namespace:System.ComponentModel;assembly=System.Windows"
xmlns:data="clr-namespace:System.Windows.Data;assembly=System.Windows"
xmlns:vm="clr-namespace:Insight.ModuleUser.ViewModels"
xmlns:command="clr-namespace:PrismFramework.Implementors.Commanding;assembly=PrismFramework"
xmlns:controls="clr-namespace:Insight.Controls;assembly=Insight.Controls"
xmlns:modalDialogs="clr-namespace:Insight.Controls.ModalDialogViews;assembly=Insight.Controls"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="1144"
d:DataContext="{d:DesignData /Insight.ModuleUser;component/SampleData/EditUserViewModelSampleData.xaml}">
<UserControl.Resources>
<command:ObservableCommand x:Name="OpenProjectCommand" Value="{Binding OpenProjectCmd}"/>
<command:ObservableCommand x:Name="OpenPaymentCommand" Value="{Binding OpenPaymentCmd}"/>
<command:ObservableCommand x:Name="OpenInvoiceCommand" Value="{Binding OpenInvoiceCmd}"/>
<command:ObservableCommand x:Name="OpenPaymentItemCommand" Value="{Binding OpenPaymentItemCmd}"/>
<command:ObservableCommand x:Name="EditPhoneCommand" Value="{Binding EditPhoneNumberCmd}"/>
<command:ObservableCommand x:Name="DeletePhoneCommand" Value="{Binding DeletePhoneNumberCmd}"/>
<command:ObservableCommand x:Name="EditEmailAddressCommand" Value="{Binding EditEmailAddressCmd}"/>
<command:ObservableCommand x:Name="DeleteEmailAddressCommand" Value="{Binding DeleteEmailAddressCmd}"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" >
<controls:AddressListView x:Name="ctrlAddressListView"
Addresses="{Binding User.Addresses}" />
</Grid>
</UserControl>
This seems a perfectly reasonable approach. However, you could use binding in your user control view, rather than setting the items source in code.
To do this you need to set the DataContext of the user control to be your user control type. This could be done either in the code behind for the user control (setting this.DataContext = this), or through element binding in XAML:
<UserControl
...
x:Name="MyName"
DataContext="{Binding ElementName=MyName}"
However, my approach would be not to use a user control at all, as all you're really talking about is view composition and reusing a particular section of the view between other views.
View composition is extremely straightforward with an MVVM framework such as Caliburn.Micro. In this case you would have an AddressViewModel and AddressView, and use a ContentControl to inject the AddressView into the base view:
<ContentControl x:Name="AddressViewModel" />

Application unable to find resource in Generic.xaml

I am working on a WPF application that uses the Telerik RAD controls for WPF. The application will be used on a PC with a touch screen, so I need to make things like pickers on the DateTimePicker control larger so they can be easily pressed by people with sausage fingers like my own.
I originally used Expression Blend to edit a copy of the control's template. That created a ControlTemplate in the UserControl's XAML file that I was designing. I have another UserControl I'm working on now that will also use the DateTimePicker, so I want to reuse the ControlTemplate.
What I did was I moved the modified template into a new named Style in the project's (a WPF Control Library) Generic.XAML. Here's a short snippet of the Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CarSystem.CustomControls"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:Telerik_Windows_Controls_Chromes="clr-namespace:Telerik.Windows.Controls.Chromes;assembly=Telerik.Windows.Controls">
<Style x:Key="RadDateTimePickerControlTemplate1" TargetType="{x:Type telerik:RadDateTimePicker}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type telerik:RadDateTimePicker}">
. . .
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Here's a snippet of the XAML where I reference the style:
<UserControl x:Class="CarSystem.CustomControls.ReportCriteria"
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:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:cs="clr-namespace:CarSystem.CustomControls"
mc:Ignorable="d"
Height="648"
Width="1117">
<Grid Background="{DynamicResource ContentBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<GroupBox BorderBrush="Black" FontSize="20" FontWeight="Bold" Grid.Row="0" Header="Report Criteria: " Margin="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="320" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="450" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="110" />
</Grid.ColumnDefinitions>
<GroupBox BorderBrush="Black" FontSize="20" FontWeight="Bold" Grid.Column="0" Header="Date Range:" Margin="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock FontSize="18"
FontWeight="Bold"
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Right"
Text="Start Date: " />
<telerik:RadDateTimePicker FontSize="18"
FontWeight="Bold"
Grid.Column="1"
Grid.Row="0"
Name="StartDatePicker"
Style="{DynamicResource RadDateTimePickerControlTemplate1}" />
<TextBlock FontSize="18"
FontWeight="Bold"
Grid.Column="0"
Grid.Row="1"
HorizontalAlignment="Right"
Text="End Date: " />
<telerik:RadDateTimePicker FontSize="18"
FontWeight="Bold"
Grid.Column="1"
Grid.Row="1"
Name="EndDatePicker"
Style="{DynamicResource RadDateTimePickerControlTemplate1}" />
</Grid>
</GroupBox>
. . .
</GroupBox>
</Grid>
</UserControl>
When I work in Expression Blend, everything looks fine. I see the change in the width of the drop down button for the control. Back in Visual Studio, everything compiles fine, but the change does not show up -- I see the default style for the control only, and the references to the style have a blue squiggly line under them. When you hover the mouse over the squiggly line, the following message is displayed:
The resource "RadDateTimePickerControlTemplate1" cannot be resolved.
The same thing happens if I change "DynamicResource" to "StaticResource" in the XAML. Also, I have made no changes to the Assembly.Info file for the project.
How do I fix this?
Thanks
Tony
As far as I remember you can't have named resources you want to reference in generic.xaml - that you have to put in app.xaml
You have to give the type in key for styles or ComponentResourceKey in key for controltemplates
and in the class static constructor override metadata like:
public class FlatStylebutton : Button
{
static FlatStylebutton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FlatStylebutton), new FrameworkPropertyMetadata(typeof(FlatStylebutton)));
}
}
So a solution to your problem could be moving the style to app.xaml
Alternatively you can put it in a separate ResourceDictionary xaml file and import it in ResourceDictionary.MergedDictionaries

Binding with multiple view models

I have a viewmodel for a usercontrol that is defined in a data template for the viewmodel. I would like to bind the 'GridViewData' property of the usercontrol to the 'Data' property of the viewmodel.
I am still new to WPF and terrible at bindings, so please be kind :p
XAML:
<Window x:Class="ReportUtility.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:lite="clr-namespace:ReportUtility.Controls.LiteGrid"
xmlns:vm="clr-namespace:ReportUtility.ViewModels"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="MainWindow" Height="350" Width="525">
<!--This is the view model I want to bind to variable name is Grid: hosted in the content control below-->
<Window.Resources>
<DataTemplate DataType="{x:Type vm:LiteGridViewModel}">
<lite:LiteGrid GridViewData="{Binding ??}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Content="TestButton" HorizontalAlignment="Stretch" Command="{Binding ExecuteQueryCommand}"/>
<TextBox Grid.Row="1" Text="{Binding Path=SqlCommandText, UpdateSourceTrigger=PropertyChanged}"/>
<ContentControl Content="{Binding Grid}" Grid.Row="2" Background="Red"/>
<Border Background="Aqua" Grid.Column="1" Grid.RowSpan="3"/>
<GridSplitter Grid.Column="0" Width="3" Grid.RowSpan="3"/>
</Grid>
You would bind to Data
<DataTemplate DataType="{x:Type vm:LiteGridViewModel}">
<lite:LiteGrid GridViewData="{Binding Data}"/>
</DataTemplate>
It would even be better to do this binding in the LiteGrid UserControl instead of relying on the XAML that uses the control to set the value.
<UserControl GridViewData="{Binding Data}">
...
</UserControl>
Your bindings always reference the current object's DataContext. Since your DataTemplate is for type LiteGridViewModel, the DataContext within that DataTemplate is always going to be of type LiteGridViewModel.
For example, if you have a class like
public class MyClassA
{
MyClassB ClassB {get; set;}
}
public class MyClassB
{
MyClassC ClassC {get; set;}
}
And a ViewModel property of MyClassA ClassA (meaning you can reference ClassA.ClassB.ClassC), you could do something like
<ContentControl Content="{Binding ClassA}">
<ContentControl Content="{Binding ClassB}"> <!-- DataContext is MyClassA -->
<ContentControl Content="{Binding ClassC}"> <!-- DataContext is MyClassB -->
<!-- DataContext is MyClassC -->
</ContentControl>
</ContentControl>
</ContentControl>

How do I allow multiple items/content for a user control in WPF?

I've managed to get as far as redirecting content to my stackpanel as shown:
<UserControl
x:Name="taskItem">
<UserControl.ContentTemplate>
<DataTemplate>
<StackPanel>
<Label x:Name="labelHeader" Content="{Binding ElementName=taskItem,Path=Header}" FontFamily="Tahoma" FontSize="16" FontWeight="Bold" />
<Border BorderThickness="0,1,0,0" BorderBrush="#999999" Margin="5,0,5,0">
<StackPanel Margin="10,5,0,0">
<ContentPresenter Content="{TemplateBinding Content}" />
</StackPanel>
</Border>
</StackPanel>
</DataTemplate>
</UserControl.ContentTemplate>
I'm trying to create a control that has a header, a line under it, and then N number of child contents. However, in it's current implementation it won't allow more than one.
What am I doing wrong here?
A user control by definition has one child since it inherits from ContentControl. Make the user control have all the headers and then make ItemsControl the content of the UserControl. Apply your DataTemplate to the ItemTemplate property of the ItemsControl.
<UserControl x:Class="WindowsApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Name="MainHeadersGrid" Grid.Row="0">
<TextBlock Text="Put your headers here" />
</Grid>
<ItemsControl Name="childItemsWillGoInHere" ItemsSource="{Binding}" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding PropertyOfItem}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
Now, assign the UserControl's template's DataContext to a collection of the objects you want to display.

Resources