How do I implement command in Page.Resources? - c#

My problem is when I'm adding command to button, which is located in ListBoxItem Style in Page.Reosources and click it, nothing happen. But if I add button in default grid, command will work.
XAML:
<Page x:Class="kkRedux.MVVM.View.SpecialView"
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:kkRedux.MVVM.View"
xmlns:viewModel="clr-namespace:kkRedux.MVVM.ViewModel"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="SpecialView">
<Page.DataContext>
<viewModel:SpecialViewModel />
</Page.DataContext>
<Page.Resources>
<Style TargetType="ListBoxItem" x:Key="DieStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Margin="11">
<Button Content="Click Mey"
Width="100" Height="100"
Background="Black"
Command="{Binding DownloadCommand}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ItemsPanelTemplate x:Key="panelTemplate">
<WrapPanel />
</ItemsPanelTemplate>
</Page.Resources>
<Grid>
<!--ItemsSource ommited-->
<ListBox Name="specialListBox"
ItemContainerStyle="{StaticResource DieStyle}"
ItemsPanel="{StaticResource panelTemplate}"
Background="Transparent"/>
<!--this Command is working-->
<Button Content="Click"
Height="100" Width="100"
Command="{Binding DownloadCommand}"/>
</Grid>
</Page>
ViewModel:
internal class SpecialViewModel
{
public RelayCommand DownloadCommand { get; set; }
public SpecialViewModel()
{
DownloadCommand = new RelayCommand<string>(o => Download(o));
}
private void Download(string arg)
{
MessageBox.Show(arg);
}
}
P.S. Click's working fine, but I can't use it due to MVVM.

Bind to the DataContext of the parent Page:
Command="{Binding DataContext.DownloadCommand,
RelativeSource={RelativeSource AncestorType=Page}}"
The default DataContext the element in the ListBox is the current item in the Items collection of the ListBox. That's why your binding doesn't work.

Related

How to tab once instead of twice in WPF

I have a simple page that allows me to associate names with bunks. Unfortunately tab isn't working as I expect. I have to tab once to get to the next item and again to get to the TextBox. This also occurs if I remove the Label control. I've searched and searched and tried a bunch of things but can't figure this one out. Any suggestions? I'm starting to get comfortable with WPF MVVM but I'm no expert.
<Page x:Class="DiverBoard.Views.ConfigurePage"
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:DiverBoard.ViewModels"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="800"
Title="ConfigurePage" Background="Navy">
<Page.DataContext>
<vm:TripViewModel/>
</Page.DataContext>
<WrapPanel>
<ListBox Background="Navy" ItemsSource="{Binding Trip.Bunks}" KeyboardNavigation.TabNavigation="Cycle">
<ListBox.Template>
<ControlTemplate>
<DockPanel LastChildFill="True">
<ItemsPresenter></ItemsPresenter>
</DockPanel>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label FontSize="18" Foreground="white" Content="{Binding Value.BunkNumber}" Width="50"></Label>
<TextBox FontSize="18" Text="{Binding Value.DiverName}" Width="200" IsTabStop="true"></TextBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</WrapPanel>
</Page>
Naturally I figured it out right after posting a question by reading something again that I had already read.
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsTabStop" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>

WANTED Two independent instances of same user control as TabItem content (section "WPF is disrespecting my code")

Uncheck the checked one, select tab "Header B" and you'll see: the unchecking has been reflected.
How can WPF think I want one instance if I place two user controls and name them differently?
WPF is driving me mad over time.
MainWindow.xaml:
<!-- The silver price is currently high? I don't care. -->
<Window x:Class="WpfApplication2.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:UserControls="clr-namespace:WpfApplication2"
mc:Ignorable="d"
Background="Silver" Title="MainWindow" FontSize="14" WindowStartupLocation="CenterScreen"
Height="300" Width="700" FocusManager.FocusedElement="{Binding ElementName=_btCancel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TabControl x:Name="_tabControl" Grid.Row="0" >
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="Content" Value="{Binding Content}" />
</Style>
</TabControl.ItemContainerStyle>
<TabItem x:Name="_tabItem_A" Header="Header A">
<TabItem.Content>
<Grid>
<UserControls:UserControl_1 x:Name="_userControl_A" />
</Grid>
</TabItem.Content>
</TabItem>
<TabItem x:Name="_tabItem_B" Header="Header B">
<TabItem.Content>
<Grid>
<UserControls:UserControl_1 x:Name="_userControl_B" />
</Grid>
</TabItem.Content>
</TabItem>
</TabControl>
<Button Name="_btCancel" Grid.Row="1" Content=" Cancel " Margin="0,10,0,10"
VerticalAlignment="Bottom" HorizontalAlignment="Center" IsCancel="True" Click="_btCancel_Click" />
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication2
{
public partial class MainWindow : Window
{
public MainWindow()
{
List<_ListViewItem> listViewItems = new List<_ListViewItem>();
listViewItems.Add(new _ListViewItem() { _IsActive = false, _Text = "Text 1" });
listViewItems.Add(new _ListViewItem() { _IsActive = true, _Text = "Text 2" });
listViewItems.Add(new _ListViewItem() { _IsActive = false, _Text = "Text 3" });
Application.Current.Resources.Add("_xamlReference_listViewContent", listViewItems);
InitializeComponent();
}
private void _btCancel_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
public class _ListViewItem
{
public bool _IsActive { get; set; }
public string _Text { get; set; }
}
}
UserControl_1.xaml:
<UserControl x:Class="WpfApplication2.UserControl_1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<CollectionViewSource x:Key="_collectionViewSource" Source="{Binding Source={StaticResource _xamlReference_listViewContent}}" />
</UserControl.Resources>
<Grid x:Name="_grid">
<ListView x:Name="_lv" Margin="10" ItemsSource="{Binding Source={StaticResource _collectionViewSource}, Mode=OneWay}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Margin" Value="0,5,0,0" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Width="70">
<GridViewColumn.Header>
<Label Content="Active" />
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=_IsActive}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="130">
<GridViewColumn.Header>
<Label Content="Interval" />
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=_Text}" HorizontalContentAlignment="Center" Width="80" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
UserControl_1.xaml.cs:
using System.Windows.Controls;
namespace WpfApplication2
{
public partial class UserControl_1 : UserControl
{
public UserControl_1()
{
InitializeComponent();
}
}
}
App.xaml:
<Application x:Class="WpfApplication2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
xmlns:UserControls="clr-namespace:WpfApplication2"
StartupUri="MainWindow.xaml">
<Application.Resources>
<!-- These brute force statements do not help: -->
<Style TargetType="{x:Type UserControls:UserControl_1}" x:Shared="False" />
<Style TargetType="{x:Type ListView}" x:Shared="False" />
</Application.Resources>
</Application>
The problem here is that both UserControls are using the same List<_ListViewItem> as their resource in this code:
<UserControl.Resources>
<CollectionViewSource x:Key="_collectionViewSource" Source="{Binding Source={StaticResource _xamlReference_listViewContent}}" />
</UserControl.Resources>
when you do this the Checkbox on both controls is bound to the same _IsActive property of the same object, so changing one will change the other. One way to fix this (see comments) is to set the binding on the check box to OneWay like this:
<CheckBox IsChecked="{Binding Path=_IsActive, Mode=OneWay}" />
Use MVVM pattern. Have two view-models (one for each tab) that share the state that's related to the checking of the checkboxes and bind the TabItem DataContext to these view-models.
Generally speaking you should avoid WPF magic when you can and use bindings/view-models to solve your problems.

Set focus of textbox in context menu - wpf

I've looked into several methods of setting focus and nothing appeared to work. I'm sure someone out there has a solution to this. It's such a simple task.
I want to set the focus of the textbox which appears in the context menu when the user right-clicks on the listbox. I don't want the user to have to click the textbox each time they right-click.
MainWindow.xaml
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox>
<ListBox.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<Border BorderThickness="2" BorderBrush="sc#1,.1,.1,.1" CornerRadius="4"
Background="sc#1,.05,.05,.05">
<TextBox Grid.Row="0" Margin="4" MinWidth="150" Name="SearchBox" VerticalAlignment="Center">
</TextBox>
</Border>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</Grid>
</Window>
IsFocused property of TextBox is read only. This forces the use of method in our case.
You need CallMethodAction behavior. Good tutorial to start with.
<TextBox Grid.Row="0" Margin="4" MinWidth="150" Name="SearchBox" VerticalAlignment="Center">
<i:Interaction.Triggers>
<ei:PropertyChangedTrigger Binding="{Binding IsOpen, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}">
<ei:CallMethodAction MethodName="FocusSearchBox" TargetObject="{Binding DataContext, ElementName=SearchBox}"/>
<ei:ChangePropertyAction PropertyName="Background" Value="Purple"/>
</ei:PropertyChangedTrigger>
</i:Interaction.Triggers>
</TextBox>
public void FocusSearchBox()
{
TextBox t = (TextBox) CtxMenu.ContextMenu.Template.FindName("SearchBox", CtxMenu.ContextMenu);
t.Focus();
}

Bind Button Command from within style template

I have a tabbed section and I am trying to wire up the commands for closing and opening new tabs dynamically. The problem is I cant understand how to bind the command from within my tabItem template(which has a button). Here is the code:
(UserControl containing the tabbed section, simplified..):
<UserControl.DataContext>
<vm:InicioViewModel />
</UserControl.DataContext>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Visual Resources/TabResource.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<ContentPresenter HorizontalAlignment="Stretch" Grid.Column="1">
<ContentPresenter.Content>
<TabControl Name="tc">
<TabControl.DataContext>
<vm:WorkSpaceViewModel/>
</TabControl.DataContext>
<TabControl ItemsSource="{Binding Items}"/>
</TabControl>
</ContentPresenter.Content>
</ContentPresenter>
</Grid>
(Here is the resource Dictionary for the tabItem):
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border x:Name="TaBorder" Width="auto" Height="auto"
BorderBrush="LightGray"
BorderThickness="0.5,0.5,0.5,0"
CornerRadius="3,3,0,0"
Background="WhiteSmoke">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<TextBlock Margin="2" Grid.Column="0" Text="{TemplateBinding Header}" />
<Button x:Name="CloseButton" Grid.Column="1" Width="11" Height="11"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Background="Transparent"
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=DataContext}"
Command="{Binding CloseWorkSpaceCommand}"
(Donkt know what yo put in command to reference my viewmodel Icommand)
BorderThickness="0"
>
<!-- ETC -->
(Here my viewModel):
class InicioViewModel : ViewModelBase
{
private WorkSpaceViewModel _workSpaceVm;
public InicioViewModel()
{
}
public WorkSpaceViewModel WorkSpaceVm
{
get { return _workSpaceVm; }
set { _workSpaceVm = value; }
}
}
(WorkSpaceViewModel..):
public class WorkSpaceViewModel
{
private ObservableCollection<IWorkSpaceItemVm> _items;
private RelayCommand _closeWorkSpaceCommand;
public WorkSpaceViewModel()
{
_items = new ObservableCollection<IWorkSpaceItemVm>();
}
public ObservableCollection<IWorkSpaceItemVm> Items
{
get { return _items; }
set { _items = value; }
}
public ICommand CloseWorkSpaceCommand
{
get
{
return _closeWorkSpaceCommand ?? (_closeWorkSpaceCommand = new RelayCommand(
param => CloseWorkSpace_Execute(param),
param => CloseWorkSpace_CanExecute(param)
));
}
}
private void CloseWorkSpace_Execute(object parm)
{
MessageBox.Show("asdasdasd");
}
private bool CloseWorkSpace_CanExecute(object parm)
{
return true;
}
}
As you can note I only have a MessageBox showing in CloseWorkSpace_Execute for test purposes.
1) How can I reference the Icommand in my viewmodel from within my tabItem style template, or, if is there a better way with same results will be welcome.
2) Why when I run the app one empty tab is created, I have my observable collection list empty
EDIT:
The RelayCommand is working OK in another part of the program, thats not the problem, The tabItem gets rendered OK with triggers workin and all, I still cant get my head into how to bind the command from my viewmodel with the Templated tabItem I made.
EDIT 2:
The command is working now, apparently the Command is not recognized in the resource dictionary and is marked as: "Cant resolve property 'CloseWorkSpaceCommand' in DataContext of type object", but setting the DataContext of the button to:
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=DataContext}"
gets the work done when running the app(visual studio still apologizing about DataContext type, dunno what it means).
There is still one tab created by default, why?
And is there a way to correct the code smell with DataContext type?
It seems like you want to add a close button on every tab like the ones we see in browsers. It's seems pretty complicated to do that. But let me try to break it down for you.
First let's start by stating the roadblocks that prevents us from doing that:
The TabItem does not have a command property where you can bind your CloseWorkSpaceCommand.
The tab item does not have a close button. That's the reason you created a Template. But still you can't do a template binding to a command property since the TabItem does not have such command property.
How will you be able wire up the button's command to the viewmodel's CloseWorkSpaceCommand property?
Now let's try to resolve each problem one by one.
To resolve this, we need to create a custom control for the TabItem that has a command property.
public class ClosableTabItem : TabItem
{
public static readonly DependencyProperty CloseCommandProperty = DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(ClosableTabItem), new PropertyMetadata(null));
public ICommand CloseCommand
{
get { return (ICommand)GetValue(CloseCommandProperty); }
set { SetValue(CloseCommandProperty, value); }
}
}
Since we have a custom tab item, we also need a custom TabControl because we need to overide the GetContainerForItemOverride() method.
public class ClosableTabControl : TabControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new ClosableTabItem();
}
}
This resolves problem #1.
Like what you did we need to have a ControlTemplate so we could place a close button on each tabs.
<ControlTemplate TargetType="{x:Type local:ClosableTabItem}">
<Border x:Name="TaBorder" Width="auto" Height="auto"
Background="LightGray" CornerRadius="4,4,0,0" Margin="0,2,3,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<TextBlock Margin="2" Grid.Column="0" Text="{TemplateBinding Header}" />
<Button x:Name="CloseButton" Grid.Column="1" Width="11" Height="11"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Command="{TemplateBinding CloseCommand}"
BorderThickness="0"
Content="X" Background="Red"
FontSize="8">
</Button>
</Grid>
</Border>
</ControlTemplate>
To bind the viewmodel.CloseWorkSpaceCommand to the tab item we do this in the ItemContainerStyle's setter.
<local:ClosableTabControl.ItemContainerStyle>
<Style TargetType="local:ClosableTabItem" BasedOn="{StaticResource {x:Type TabItem}}">
<Setter Property="CloseCommand" Value="{Binding DataContext.CloseWorkSpaceCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" /> ...
You'll notice that I'm using relative source to the DataContext of the Window.
Now to bind the CloseCommand Property of the ClosableTabItem to the Command property of the Button inside the template, we now do the template binding inside the control template's button.
You can also see this in answer #2 code sample.
Command="{TemplateBinding CloseCommand}"
Here's the complete xaml code:
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<local:ClosableTabControl ItemsSource="{Binding Items}">
<local:ClosableTabControl.ItemContainerStyle>
<Style TargetType="local:ClosableTabItem" BasedOn="{StaticResource {x:Type TabItem}}">
<Setter Property="CloseCommand" Value="{Binding DataContext.CloseWorkSpaceCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ClosableTabItem}">
<Border x:Name="TaBorder" Width="auto" Height="auto"
Background="LightGray" CornerRadius="4,4,0,0" Margin="0,2,3,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<TextBlock Margin="2" Grid.Column="0" Text="{TemplateBinding Header}" />
<Button x:Name="CloseButton" Grid.Column="1" Width="11" Height="11"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Command="{TemplateBinding CloseCommand}"
BorderThickness="0"
Content="X" Background="Red"
FontSize="8">
</Button>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:ClosableTabControl.ItemContainerStyle>
<TabControl.Items>
</TabControl.Items>
</local:ClosableTabControl>
</Grid>
</Window>

Binding to DataGrid of TabItem not Working using MVVM

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}"/>
</DataTemplat‌​e>
</TabControl.ContentTemplate>

Categories

Resources