Customize Dialog window prism - c#

I have implemented the new DialogService as shown in this issue
A New IDialogService for WPF
However, this doesn't explain how to edit the window of the dialog itself, since the NotificationDialog is a UserControl.
I have tried changing it to a Window but then an exception is raised due to not being the root Window.
Any idea how can I change the Window of the dialog?
Since the Title and the Icon is set in DialogViewModelBase, I have tried to add a ResizeMode property as well.
In DialogViewModelBase:
private ResizeMode _resizeMode;
public ResizeMode ResizeMode
{
get => _resizeMode;
set => SetProperty(ref _resizeMode, value);
}
and in NotificationDialogViewModel implementation:
public NotificationDialogViewModel()
{
Title = "Notification";
ResizeMode = System.Windows.ResizeMode.CanMinimize;
CloseDialogCommand = new DelegateCommand(CloseDialog);
}
However it doesn't work as intended.

For others who search for this - the style can be set using prism:Dialog.WindowStyle.
Example from
https://github.com/PrismLibrary/Prism/blob/master/Sandbox/Wpf/HelloWorld/HelloWorld/Dialogs/NotificationDialog.xaml
New link: https://prismlibrary.com/docs/wpf/dialog-service.html#style-the-dialogwindow
<UserControl x:Class="HelloWorld.Dialogs.NotificationDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Width="300" Height="150">
<prism:Dialog.WindowStyle>
<Style TargetType="Window">
<Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterScreen" />
<Setter Property="ResizeMode" Value="NoResize"/>
<Setter Property="ShowInTaskbar" Value="False"/>
<Setter Property="SizeToContent" Value="WidthAndHeight"/>
</Style>
</prism:Dialog.WindowStyle>
<Grid x:Name="LayoutRoot" Margin="5">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Message}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" TextWrapping="Wrap" />
<Button Command="{Binding CloseDialogCommand}" CommandParameter="True" Content="OK" Width="75" Height="25" HorizontalAlignment="Right" Margin="0,10,0,0" Grid.Row="1" IsDefault="True" />
</Grid>
</UserControl>
Other properties can also be set using Setter. For example,
<Setter Property="WindowStyle" Value="None" />
will hide the title bar.

Any idea how can I change the Window of the dialog?
Looking at the code, it looks like you have to implement IDialogWindow and override the default registration to the built-in implementation.
Also, you don't need to inherit from DialogViewModelBase, just implementing IDialogAware suffices.

Related

How to 'Disable' a WPF UserControl?

I have a UserControl, and I need to change its appearance when 'IsEnabled' is false. I know this is pretty basic WPF styling, but I can't seem to put the pieces together. I assume that I need to create a Style, and add a trigger for "Property="IsEnabled" Value="False". But where do I put the Style definition? (<UserControl.Resources>?) How do I apply it? ... in the UserControl or in the Parent window? Does my trigger need to be inside a Setter element? Does the style need to be applied to the UserControl or to its children? I don't know what other questions I need to ask!
If you feel this is a duplicate of another question, please direct me to it.
If you know of a good, simple tutorial on WPF styling that would answer my questions, I would be very grateful to hear of it.
My code looks like this:
<UserControl x:Class="UserControls.UCDemo"
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:UserControls"
mc:Ignorable="d"
d:DesignHeight="240" d:DesignWidth="200">
<UserControl.Resources>
</UserControl.Resources>
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="5*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="{Binding BG}" >
<Ellipse Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5" Fill="DeepSkyBlue" />
</Grid>
<Grid Grid.Row="1" Background="Tomato" />
</Grid>
<uc:UCDemo x:Name="Demo" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="300,100,0,0" Width="80" Height="100" Style="{StaticResource uc:DemoStyle}"
Visibility="{Binding LightVisible, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Converter={StaticResource BooleanToVisibilityConverter}}" />
Thank you for your help!
It depends on how exactly the appearance should change when IsEnabled is false.
A simple Style with a Trigger could be assigned directly to the UserControl's Style property. The one below just sets the Opacity to 0.5.
<UserControl ...>
<UserControl.Style>
<Style TargetType="UserControl">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Style>
<Grid Background="Transparent">
...
</Grid>
</UserControl>
I'm not sure I get what your question is. However in order to change the IsEnabled property of a control, depending on an other controls is:
Let's suppose that the control which its IsEnabled must be changed, is A and the control which A is depends on, is B.
First, choose a name for B: x:Name = "AccessCheckBox".
Then Write a binding like this for control B:
< ... IsEnabled = {Binding ElementName = "AccessCheckBox", Path="IsChecked".../>
Done. I hope I got what you mean.

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>

How to add Close Button in tab of Dynamic WPF Tab control

I have a WPF Tab Control..
i am adding tabs in that TabControl dynamically
Now i want to give a Close Button in every Tab of Tab Control..
So please tell me hopw to add Close button in that Tab Control..
Code for adding tab
private void AddTab(ITabbedMDI mdiChild)
{
if (_mdiChildren.ContainsKey(mdiChild.UniqueTabName))
{
//user control is already opened in tab.
//So set focus to the tab item where the control hosted
foreach (object item in tcMdi.Items)
{
TabItem ti = (TabItem)item;
if (ti.Name == mdiChild.UniqueTabName)
{
ucChildLoc = (UserControl)mdiChild;
ti.Focus();
//tcMdi.Width = this.ucChildLoc.Width;
//tcMdi.Height = this.ucChildLoc.Height;
break;
}
}
}
}
Code for Closing tab
private void CloseTab(ITabbedMDI tab, EventArgs e)
{
TabItem ti = null;
foreach(TabItem item in tcMdi.Items)
{
if (tab.UniqueTabName == ((ITabbedMDI)item.Content).UniqueTabName)
{
ti = item;
break;
}
}
if (ti != null)
{
_mdiChildren.Remove(((ITabbedMDI)ti.Content).UniqueTabName);
tcMdi.Items.Remove(ti);
}
}
I am using TabControl of this article
http://www.codeproject.com/Articles/32362/Tabbed-MDI-in-WPF
Thanks in Advance..
I have tried several solutions and struggled to find something that looked nice and also highlighted the "X" in the button when the mouse hovers. I finally ended with this one. It also does not require too much code. I hope it helps:
<TabControl>
<TabItem>
<TabItem.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0">Output</TextBlock>
<Button Grid.Column="1" Name="button_close" Click="button_close_Click">
<Button.Template>
<ControlTemplate TargetType="Button">
<Path Data="M0,0 L8,8 M8,0 L0,8" StrokeThickness="3" VerticalAlignment="Center" Margin="5,4,0,2">
<Path.Style>
<Style TargetType="{x:Type Path}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Stroke" Value="LightGray" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</TabItem.Header>
<TabItem.Content>
</TabItem.Content>
if you make the tab control as a custom control and inherit the functionality from tab control and then add close button and handle its events then it can work
<UserControl x:Class="CloseableHeader"
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="23" d:DesignWidth="81" Margin="0">
<Grid>
<Button Content="X" Height="19" HorizontalAlignment="Right" Margin="0,3,4,0"
Name="button_close" VerticalAlignment="Top" Width="20" FontFamily="Courier"
FontWeight="Bold" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
FontStretch="Normal" Visibility="Visible"
FontSize="14" Padding="0" ToolTip="Close"/>
<Label Content="TabItem" Height="23" HorizontalAlignment="Left"
Margin="4,1,0,0" Name="label_TabTitle" VerticalAlignment="Top"
FontFamily="Courier" FontSize="12" />
</Grid>
class ClosableTab : TabItem
{
// Constructor
public ClosableTab()
{
// Create an instance of the usercontrol
closableTabHeader = new CloseableHeader();
// Assign the usercontrol to the tab header
this.Header = closableTabHeader;
}
}
see in this article for details http://www.codeproject.com/Articles/84213/How-to-add-a-Close-button-to-a-WPF-TabItem
this might be helpful
TabControl does not provide the ability to close TabItems.
You could add a 'x' button and set the visibility to Collapsed / Hidden as a hack.
OR You could look at XamTabControl by Infragistics or any other vendor product which does support closing of Tabs.

ContentPresenter in UserControl

I'm new to WPF and I'm trying to create an UserControl which will have some nested content.
<my:InformationBox Header="General Information" Width="280">
<StackPanel>
<Label>Label1</Label>
<Label>Label2</Label>
</StackPanel>
</my:InformationBox>
As you can see I want to put a StackPanel into it. As I read some articles I am supposed to add ContentPresenter to my UserControl, so I did, but I cannot find what should be binded to it's Content property.
Here is my UserControl code
<UserControl x:Class="ITMAN.InformationBox"
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="200" d:DesignWidth="280" Name="infoBox" Loaded="infoBox_Loaded">
<StackPanel Width="{Binding ElementName=infoBox, Path=Width}" HorizontalAlignment="Stretch">
<Label Content="{Binding ElementName=infoBox, Path=Header}" />
<Border BorderThickness="0,1,0,0" Padding="10 5" Margin="5 0 5 10" BorderBrush="#B4CEDE">
<StackPanel>
<ContentPresenter Content="{Binding Content}" />
<Label Content="End" />
</StackPanel>
</Border>
</StackPanel>
</UserControl>
I've tried many combinations from various articles, but I cannot find any working example of what I want to achieve.
Similiar question was asked earlier by another user, but given there answers didn't help me: Does anyone have a simple example of a UserControl with a single ContentPresenter?
ContentPresenter is kind of a magic control. If you don't supply anything to it, it will automatically set the Content, ContentTemplate and ContentTemplateSelector property with a TemplateBinding to the TemplatedParent. Which means, you don't need to supply anything to it, just
<ContentPresenter/>
in your UserControl, and it should automatically use the corresponding properties found in your UserControl.
Also remember that a binding like {Binding Content} always referes to your DataContext, which i guess is not what you wanted.
I solved this problem by applaying custom style to GroupBox. I've created Syle in ResourceDictionary, which looks as follows
<Style x:Key="InformationBoxStyle" TargetType="GroupBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label>
<ContentPresenter Margin="4" ContentSource="Header"
RecognizesAccessKey="True" />
</Label>
<Border Grid.Row="1" BorderThickness="0,1,0,0" Padding="10 5"
Margin="5 0 5 10" BorderBrush="#B4CEDE">
<StackPanel>
<ContentPresenter />
</StackPanel>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And applied this style to GroupBox
<GroupBox Header="General Information" Width="280" Style="{StaticResource InformationBoxStyle}">
<StackPanel>
<Label>Label1</Label>
<Label>Label2</Label>
</StackPanel>
</GroupBox>
This code works as expected
You may also refer to this great article, which shows different options to achieve it:
http://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control
It also describes why ContentPresenter doesn't work in my code.
You need to create a dependency property on your UserControl code behind such as InnerContent.
public object InnerContent
{
get { return GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof(object), typeof(ConfirmationControl), new PropertyMetadata(null));
Then you need to bind to that InnerContent on the XAML side of that UserControl.
<ContentControl Content="{Binding InnerContent, ElementName=userControl}" />
Then when you use it instead of placing content in the UserControl directly and overwriting the existing content just add it to the InnerContent portion.
<UserControls:InformationBox>
<UserControls:InformationBox.InnerContent>
<TextBlock Text="I'm in the InnerContent" />
</UserControls:InformationBox.InnerContent>
</UserControls:InformationBox>
Otherwise using a Template or Style is just as good but if you're wanting to package up a UserControl for use without forcing anyone to also reference a style or template this is probably one of your better options.

Categories

Resources