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.
Related
I'm working on making a simple tic-tac-toe game to familiarize myself with WPF, due to the amount of time it's been since I've used the format. I've been trying to disable the button, to prevent people from choosing the same square, after the content has been set to X or O. Here is a sample of my XAML code for the buttons:
<Button Name="btmRight" Margin="10 10 10 10" Grid.Column="2" Grid.Row="2" FontSize="128">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="1"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
The buttons are enabled by default. I then use some simple C# code to disable the button, and set the content to X or O depending on the turn. However, despite the style trigger being in each button, the format is never changed. Something I might explore is putting a conditional in the code, to not change anything with the buttons if they have content, rather than disabling the button when it's clicked. Here is a sample of what I'm using for the C#:
mid.Click += (sender, e) =>
{
mid.Content = mark;
TurnSwap();
mid.IsEnabled = false;
IsComplete();
};
"mark" is a String that is set depending on the turn. The content is set to the mark value, which then rotates immediately after the content is set. The button is then disabled, and the game checks to see if someone has won yet. If I were to go with the option of manually disabling the button, I would surround that C# code in a conditional, to check if the content = "", which it is by default. I feel this option is a bit lazy, and I would like to learn the WPF solution for the concepts alone.
The following code is just a sample based on your question. I does not have tic-tac-toe game logic implemented.
It demonstraits how to implement common style to button and also implmentation of common ClickEvent.
You can use it and change it as per you need.
XAML
<Window x:Class="WPFTest.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:WPFTest"
mc:Ignorable="d"
Title="TestWPF" Height="300" Width="400"
WindowStyle="None" WindowStartupLocation="CenterScreen">
<Window.Resources>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Background" Value="MediumAquamarine" />
<Setter Property="Foreground" Value="MediumBlue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter x:Name="MyContentPresenter"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="1"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="btn1" Grid.Row="0" Grid.Column="0" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn2" Grid.Row="0" Grid.Column="1" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn3" Grid.Row="0" Grid.Column="2" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn4" Grid.Row="1" Grid.Column="0" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn5" Grid.Row="1" Grid.Column="1" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn6" Grid.Row="1" Grid.Column="2" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn7" Grid.Row="2" Grid.Column="0" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn8" Grid.Row="2" Grid.Column="1" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
<Button x:Name="btn9" Grid.Row="2" Grid.Column="2" Style="{StaticResource buttonStyle}" Click="btn_Click"/>
</Grid>
</Window>
CS
using System;
using System.Windows;
using System.Windows.Controls;
namespace WPFTest
{
public partial class MainWindow : Window
{
string sign = "X";
public MainWindow()
{
InitializeComponent();
}
private void btn_Click(object sender, RoutedEventArgs e)
{
try
{
Button currentButton = sender as Button;
currentButton.Content = sign;
currentButton.IsEnabled = false;
swapSign();
}
catch (Exception ex)
{
}
}
private void swapSign()
{
if (sign == "X")
sign = "O";
else
sign = "X";
}
}
}
UPDATE-1
I changed the style in XAML. Check above. One thing to note here is that you have to set Background and Foreground properties of Button Style like I set.
I have a textbox style with button to clear value of textbox,
but when the event click on button, the value disappear and reappear when release the button mouse.
below the xaml code:
<ResourceDictionary .....
<Style x:Key="SearchBoxTemplate" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderBrush="LightGray" BorderThickness="1">
<StackPanel Orientation="Horizontal" >
<Grid Width="{TemplateBinding Width}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8.6*" />
<ColumnDefinition Width="1.4*" />
</Grid.ColumnDefinitions>
<TextBox Background="Transparent" x:Name="searchTextBox" Grid.Column="0"
HorizontalAlignment="Stretch" BorderThickness="0"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text, Mode=TwoWay}"
Height="{TemplateBinding Height}" />
<Button Background="Transparent"
x:Name="clearButton" Content="X"
Margin="2" Width="Auto" Height="Auto"
Grid.Column="1"/>
</Grid>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="clearButton" Property="IsPressed" Value="True" >
<Setter TargetName="searchTextBox" Property="TextBox.Text" Value="" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And use like:
<TextBox Style="{StaticResource SearchBoxTemplate}"
Width="200"
Text="{Binding SearchLastName,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}" />
// C# SearchViewModel
internal class SearchViewModel : ViewModelBase
{
private string _searchLastName;
public string SearchLastName
{
get { return this._searchLastName; }
set
{
this._searchLastName = value;
OnPropertyChanged("SearchLastName");
}
}
......
How, and is it possible?
someone can help me?
Regards
I don't think it's possible to do this in quite the way you're atttempting (although I could be wrong).
My understanding is that in the first instance (before the button is pressed), your TextBox named searchTextBox will be obtaining its value from the Path specified in the ParentTemplate, the TextBox.Text property - which is bound to your local SearchLastName property.
When you press the button, you're overriding the binding which has been set on the searchTextBox control, so that the value of TextBox.Text is no longer obtained from the bound Path to SearchLastName, it is instead simply set to the empty string literal "", which is what you see displayed (set from your ParentTemplateTrigger).
Once the button is released, the binding reverts back to the previous Path to your property, which has never been changed, and will remain the same.
If you want to actually the clear the SearchLastName property, you'll either have to make the button fire a command/action which clears your search, or manipulate Text property of the control (which I believe there are ways to do entirely within the UI with relative bindings, but it may be a tricky solution for a simple problem). I don't believe you'll be able to do it with switching templates.
Triggers will automatically perform operations for IsPressed="False". Write a trigger that listens for IsPressed="False".
Updated answer:
<Style x:Key="SearchBoxTemplate" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderBrush="LightGray" BorderThickness="1">
<StackPanel Orientation="Horizontal" >
<Grid Width="{TemplateBinding Width}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8.6*" />
<ColumnDefinition Width="1.4*" />
</Grid.ColumnDefinitions>
<TextBox Background="Transparent" x:Name="searchTextBox" Grid.Column="0"
HorizontalAlignment="Stretch" BorderThickness="0"
Height="{TemplateBinding Height}" />
<Button Background="Transparent"
x:Name="clearButton" Content="X"
Margin="2" Width="Auto" Height="Auto"
Grid.Column="1"/>
</Grid>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="clearButton" Property="IsPressed" Value="True" >
<Setter TargetName="searchTextBox" Property="Text" Value="" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<TextBox Style="{StaticResource SearchBoxTemplate}"
Width="200"
Text="{Binding SearchLastName,Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged
}" />
ViewModel:
internal class SearchViewModel : INotifyPropertyChanged
{
public void RaisePropertyChanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private string _searchLastName=string.Empty;
public string SearchLastName
{
get { return _searchLastName; }
set
{
_searchLastName = value;
RaisePropertyChanged("SearchLastName");
}
}
}
First issue is you are missing UpdateSourceTrigger = PropertyChanged on TextBox inside template. Default value for TextBox is LostFocus. You need to set it to PropertyChanged in case you want source property to be updated while typing in textBox.
<TextBox Background="Transparent" x:Name="searchTextBox" Grid.Column="0"
HorizontalAlignment="Stretch" BorderThickness="0"
Text="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Height="{TemplateBinding Height}" />
Second, you have used Trigger on IsPressed value of button. So, it will revert once IsPressed value gets reversed. IsPressed state is transient, you need to update the bound property on Click event which you can achieve via EventTrigger but sadly it cannot have setter inside.
So, you should change the Text by binding it to ICommand in ViewModel and simply set the underlying bound property from command method.
Finally with your comments I did this:
In SearchviewModel
.....
private ICommand clearCommand;
public ICommand ClearCommand
{
get
{
if (this.clearCommand == null)
this.clearCommand = new RelayCommand(() => this.ClearSearch(), ()=> CanSearch());
return this.clearCommand;
}
}
void ClearSearch()
{
Search = string.Empty;
}
bool CanSearch()
{
return !string.IsNullOrEmpty(_search);
}
.....
In style
<Style....
<Button
....
Command="{Binding ClearCommand}" />
</Style>
And I have removed Trigger
It's Work fine, but I wanted the pure xaml.
Many thanks to all :)
Best regards
I am adding a WPF DatePicker control to my form and it works fine. But I don't want the user to be able to type in a type in the 'Select a date' textbox. I want that to be readonly and when they click the textbox it just opens the calendar.
I wasn't sure if there was an option for this in the properties? I couldn't find anything...
<DatePicker HorizontalAlignment="Left" VerticalAlignment="Top">
<DatePicker.Resources>
<Style TargetType="DatePickerTextBox">
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="Text" Value=" "/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="IsEnabled" Value="False" />
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
</DatePicker.Resources>
</DatePicker>
In future you can use the WPF visualizer to see which child controls a top-level control is using (in this case DatePickerTextBox) and then apply a style and/or template to that type in the resources section like I've done here.
The answer of Mark Feldman is partially right, he had not answer to how clicking on the textbox gonna open the calendare popup!
You should hook the template of the DatePicker and enlarge the size of the button so it will overlap the textbox: then you are done, when you click on the textbox it's the button that get the event see below a part of the modified template of DatePicker:
<DatePickerTextBox Grid.Row="0" Grid.Column="0" x:Name="PART_TextBox" Focusable="{TemplateBinding Focusable}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>
<Button Grid.Row="0" Grid.Column="0" x:Name="PART_Button" Foreground="{TemplateBinding Foreground}" Focusable="False" >
<Button.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Background="Transparent"/>
<Button Grid.Column="1" HorizontalAlignment="Left" Foreground="{TemplateBinding Foreground}" Template="{StaticResource DropDownButtonTemplate}" VerticalAlignment="Top" Width="20" Margin="3,0,3,0" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
Dont forget to add the style of DatePickerTextBox described in the answer of Mark Feldman
You can open calendar this way :
<DatePicker Name="datePicker" Focusable="False">
<DatePicker.Resources>
<Style TargetType="DatePickerTextBox">
<EventSetter Event="MouseLeftButtonUp" Handler="OnMouseLeftButtonUp" />
</Style>
</DatePicker.Resources>
</DatePicker>
private void OnMouseLeftButtonUp(object sender, RoutedEventArgs e)
{
datePicker.IsDropDownOpen = true;
}
How can I set Visibility="Visible" for the Button inside the Control Template when the IsSendBtnVisible property in the code-behind is true?
Here's my WPF page:
<Page
x:Class="CardViewPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CardViewPage">
<Grid Name="content" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DocumentViewer Margin="0" Grid.Row="0" Name="documentViewer" />
</Grid>
</Page>
Here's my Custom Template for the document viewer on this page:
<Style TargetType="{x:Type DocumentViewer}">
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DocumentViewer}">
...
<Button
Click="btnSendToServer_Click"
Width="25"
Height="25"
Visibility="Collapsed" />
...
</ControlTemplate>
</Setter>
...
</Style>
U need to declare DependancyProperty for ur DocumentViewer and use TemplateBinding in xaml ControlTemplate (UrProperty for example)
<ControlTemplate TargetType="{x:Type DocumentViewer}">
...
<Button Click="btnSendToServer_Click"
Width="25"
Height="25"
Visibility="{TemplateBinding UrProperty}"
/>
...
</ControlTemplate>
I suggest you to use data triggers to achieve this...
<Button
Click="btnSendToServer_Click"
Width="25"
Height="25">
<Button.Style>
<Style>
<Setter Property="Button.Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSendBtnVisible}" Value="True">
<Setter Property="Button.Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Make sure to set visibility to collapsed in the style but not in the button properties..
Note: Binding for data trigger may change depending on your data context
Dima Martovoi,bathineni - thanks for replies.
Dima Martovoi, i think inherit from DocumentViewer is to hard for this small problem.
I tried to use variant with DataTrigger from bathineni's solution, but it's not works. Don't know, why.
Problem was solved using next binding:
<Button
Visibility="{Binding RelativeSource={RelativeSource AncestorType=Page},Path=SendToServerVisiblity}">
</Button>
where
public Visibility SendToServerVisiblity
{
get
{
if (IsOnlineMode)
return Visibility.Visible;
return Visibility.Collapsed;
}
}
in page code-behind
I have created a nested WPF Datagrid. I see you can expand it by clicking on the row, but it doesn't collapse when you do the same thing.
Few questions:
How can the user collapse the grid?
Is there a way to get Expand/Collapse buttons on the parent rows?
Whenever you click on a different parent to expand, it collapses the previous one you are on. Is there a way to get the grid to stay the way you make it. i.e. If I expand row 1 then go to row 3, row 1 will stay where I expanded it to.
Thanks,
Greg
There are couple approaches to reach such behavior.
For example
Expand/Collapse button in a Silverlight DataGrid.
If you prefer xaml then use:
<Style x:Key="ExpandableDataGridRowHeaderStyle"
TargetType="sdk:DataGridRowHeader">
<Setter Property="Background"
Value="#99E9EEF4" />
<Setter Property="IsTabStop"
Value="False" />
<Setter Property="SeparatorBrush"
Value="#FFFFFFFF" />
<Setter Property="SeparatorVisibility"
Value="Collapsed" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdk:DataGridRowHeader">
<Grid x:Name="Root">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border BorderBrush="#FFFFFFFF"
BorderThickness="1,0,1,0"
Grid.ColumnSpan="2"
Grid.RowSpan="3">
<Grid>
<Rectangle x:Name="RowInvalidVisualElement"
Grid.ColumnSpan="2"
Fill="#FFF7D8DB"
Opacity="0"
Grid.RowSpan="3"
Stretch="Fill" />
<Rectangle x:Name="BackgroundRectangle"
Grid.ColumnSpan="2"
Fill="Transparent"
Grid.RowSpan="3"
Stretch="Fill" />
</Grid>
</Border>
<Button Background="{x:Null}"
BorderBrush="{x:Null}"
BorderThickness="0"
Padding="0"
Grid.RowSpan="1"
HorizontalAlignment="Stretch">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<AttachedBehaviors:ExpandButtonAction/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And AttachedBehavior that actually will change DetailsVisibility:
public class ExpandButtonAction : TargetedTriggerAction<FrameworkElement>
{
#region Invoke
protected override void Invoke(object parameter)
{
RoutedEventArgs eventArgs = (RoutedEventArgs) parameter;
Button bsender = eventArgs.OriginalSource as Button;
var row = DataGridRow.GetRowContainingElement(eventArgs.OriginalSource as FrameworkElement);
if (row.DetailsVisibility == Visibility.Visible)
{
row.DetailsVisibility = Visibility.Collapsed;
}
else
{
row.DetailsVisibility = Visibility.Visible;
}
}
#endregion
}
And apply this for RowHeaderStyle of DataGrid where you want to expand/collapse DetailsTemplate.
Use WPF Expander. So that you can expand the inner DataGrid.