WPF Creating a multi use control - wpf

I'm trying to create a WPF window that has a single control and 2 buttons displayed.
The control can be either a TextBox, ComboBox or Slider dependent on the type of object selected to launch this window.
Is it possible to do this or will I have to create a window with 3 conrtols and manipulate their position at runtime?
Regards
Tony
additions to original question
My implementation is as follows
<Window.Resources>
<Style TargetType="TextBox" x:Key="TextBoxTemplate">
<Setter Value="{Binding ElementName=MyWindow, Path=m_csValue}" />
</Style>
<Style TargetType="{x:Type ComboBox}" x:Key="ComboBoxTemplate">
<Setter Value="{Binding ElementName=MyWindow, Path=ItemsForSelection}" />
</Style>
<Style TargetType="{x:Type Slider}" x:Key="SliderTemplate">
<Setter Value="{Binding ElementName=MyWindow, Path=SliderDetail}" />
</Style>
<Style TargetType="{x:Type ContentControl}" x:Key="DisplayValues">
<!-- Default Template -->
<Setter Property="ContentTemplate" Value="{StaticResource TextBoxTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyWindow, Path=eType}" Value="{x:Static local:eTagDisplay.Text}">
<Setter Property="ContentTemplate">
<Setter.Value>
<ControlTemplate Template="{StaticResource TextBoxTemplate}" />
</Setter.Value>
</Setter>
</DataTrigger>
<!-- DataTrigger Binding="{Binding ElementName=MyWindow, Path=eType}" Value="{x:Static local:eTagDisplay.Combo}">
<Setter Property="ContentTemplate">
<Setter.Value>
<ControlTemplate Template="{StaticResource ComboBoxTemplate}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=MyWindow, Path=eType}" Value="{x:Static local:eTagDisplay.Slider}">
<Setter Property="ContentTemplate">
<Setter.Value>
<ControlTemplate Template="{StaticResource SliderTemplate}" />
</Setter.Value>
</Setter>
</DataTrigger -->
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Width="267">
<StackPanel Name="TagEditor1">
<!-- Text="{Binding ElementName=MyWindow, Path=m_csValue}" / -->
<ContentControl Style="{StaticResource DisplayValues}" />
</StackPanel>
<Button Content="OK" Height="23" HorizontalAlignment="Left" Margin="12,154,0,0" Name="btnOK" VerticalAlignment="Top" Width="75" Click="OnClkOK" />
<Button Content="Cancel" Height="23" HorizontalAlignment="Left" Margin="180,154,0,0" Name="btnCancel" VerticalAlignment="Top" Width="75" Click="OnClkCancel" IsCancel="True" />
</Grid>
I'm getting an error 'System.Windows.Style' is not a valid value for the 'System.Windows.Controls.ContentControl.ContentTemplate' property on a setter. I don't know why this is happening.
My Binding is OK, i believe, as it picks up string OK....

I would do this with a <ContentControl> that has a different <ContentTemplate> depending on what type of control is needed.
You didn't specify how the control type is being passed to the window, so your DataTrigger bindings would probably look a bit different from mine, but this should give you the right idea:
<DataTemplate TargetType="{x:Type ContentControl}" x:Key="TextBoxTemplate">
<TextBox ... />
</DataTemplate>
<DataTemplate TargetType="{x:Type ContentControl}" x:Key="ComboBoxTemplate">
<ComboBox ... />
</DataTemplate>
<DataTemplate TargetType="{x:Type ContentControl}" x:Key="SliderTemplate">
<Slider ... />
</DataTemplate>
<Style x:Key="MyStyle" TargetType="{x:Type ContentControl}">
<!-- Default Template -->
<Setter Property="ContentTemplate"
Value="{StaticResource TextBoxTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding SomeBoundValue}" Value="ComboBox">
<Setter Property="ContentTemplate"
Value="{StaticResource ComboBoxTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding SomeBoundValue}" Value="Slider">
<Setter Property="ContentTemplate"
Value="{StaticResource SliderTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
...
<ContentControl Style="{StaticResource MyStyle}" />
You could also allow users to specify a Content for your UserControl or Window, and simply display it using a ContentPresenter bound to the Content. Something like this:
<UserControl.Template>
<StackPanel>
<ContentPresenter Content="{TemplateBinding Content}" />
<Button ... />
<Button ... />
</StackPanel>
</UserControl.Template>
then you could use it like this:
<local:MyUserControl>
    <TextBox ... />
</local:MyUserControl>
<local:MyUserControl>
<ComboBox ... />
</local:MyUserControl>
<local:MyUserControl>
<Slider ... />
</local:MyUserControl>

I think it is possible with single window.By exposing a property that sets visibilty based on some condition.
i.e textbox visibility is set to visibility.visible and combobox,slider visibilty is set to visibility.collpased.similarly if you want to have combobox visible you make that visible and others collapsed.similarly for slider.
example:
public Visibility TextboxVisibility
{
set
{
Visibility visible = value;
Textboxname.Visibility = visible ;
}
}
I hope this answers your question

Related

How can I get a strikethrough decoration applied to a label via a trigger?

There are a zillion examples of how to do this to a TextBlock, but I need it on a label. I thought the default template for a label included a TextBlock, so I tried this:
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Included}" Value="False">
<Setter Property="TextBlock.TextDecorations" Value="Strikethrough" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Label Grid.Column="0" BorderThickness="0,1,0,0" BorderBrush="White"
Background="Transparent" Padding="5,0,5,0"
Content="{Binding Path=BillingDefinitionId}"
IsEnabled="{Binding Path=Included}" />
</Grid>
The effect I am going for is when Included is false, the label should be disabled and have strikethrough text. But this is not working for the strikethrough bit.
If I explicity declare the TextBlock, then it seems to work:
<Grid.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Included}" Value="False">
<Setter Property="TextDecorations" Value="Strikethrough" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Label Grid.Column="0" BorderThickness="0,1,0,0" BorderBrush="White"
Background="Transparent" Padding="5,0,5,0"
HorizontalContentAlignment="Right" VerticalContentAlignment="Center"
IsEnabled="{Binding Path=Included}">
<TextBlock Text="{Binding Path=BillingDefinitionId}" />
</Label>
I suppose that's fairly simple, not sure why it didn't occur to me prior to posting, but it seems a bit overkill if the default template is a TextBlock… Regardless, it works.

xaml User control layout -Sizing

I have a parent user control which has a detail section and a tree section in it. My intention is on two toggle button i should be able to hide and show the controls.
<DockPanel>
<DockPanel DockPanel.Dock="Left">
<view:ListBoxUserControl DockPanel.Dock="Top" Visibility="{Binding IsListVisible ,Converter={StaticResource BoolToVisibilityConverter}}"/>
<view:TreeUserControl DockPanel.Dock="Top" Visibility="{Binding IsTreeVisible,Converter={StaticResource BoolToVisibilityConverter}}"/>
</StackPanel>
<view:DetailSectionUserControl/>
</StackPanel>
IsListVisible and IsTreeVisible is set based on two toggle button in the view.
so when IsListVisible is false the ListBoxUserControl will be hidden and TreeUserControl will move to top. this is working well.
But there are two problems here i face.
1) Requirement is that the both controls should be having same size. here the first tree will be created based on the items in it and rest of the space will be taken by TreeUserControl. How shall i make the size even.
2) When i add an item to ListBoxUserControl the control just grows and TreeUserControl size get reduced. How shall i get a scroll instead .
Try:
<Grid>
<Grid.RowDefinitions>
<RowDefinition>
<RowDefinition.Style>
<Style TargetType="{x:Type RowDefinition}">
<Setter Property="Height" Value="*" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsListVisible}" Value="False">
<Setter Property="Height" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</RowDefinition.Style>
</RowDefinition>
<RowDefinition>
<RowDefinition.Style>
<Style TargetType="{x:Type RowDefinition}">
<Setter Property="Height" Value="*" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsTreeVisible}" Value="False">
<Setter Property="Height" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</RowDefinition.Style>
</RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<view:ListBoxUserControl Visibility="{Binding IsListVisible ,Converter={StaticResource BoolToVisibilityConverter}}"/>
</ScrollViewer>
<view:TreeUserControl Grid.Row="1" Visibility="{Binding IsTreeVisible,Converter={StaticResource BoolToVisibilityConverter}}"/>
</Grid>

using text box and label inheritance

IM using lot of text boxes and label that have lot of common beside ,my question is if
in wpf instead of copy paste ?
for example if I have the following text box and instead the name and the place on the screen
I want that all text box have the same behaviors
<TextBox x:Name="name2"
AcceptsReturn="True"
AllowDrop="True"
PreviewDragEnter="DropText_PreviewDragEnter"
PreviewDrop="DropText_PreviewDrop"
PreviewDragOver="DropText_PreviewDragOver"
HorizontalAlignment="Left" Height="20" TextWrapping="Wrap"
VerticalAlignment="Top" Width="80" Grid.Column="4" Margin="4,50,0,0" Grid.Row="2"
/>
<TextBox x:Name="name1"
AcceptsReturn="True"
AllowDrop="True"
PreviewDragEnter="DropText_PreviewDragEnter"
PreviewDrop="DropText_PreviewDrop"
PreviewDragOver="DropText_PreviewDragOver"
HorizontalAlignment="Left"
Height="20"
TextWrapping="Wrap"
Text="" VerticalAlignment="Top" Width="80" Grid.Column="4" Margin="4,75,0,0" Grid.Row="2"/>
You can use Style, which will store all the settings for the control:
<Style TargetType="{x:Type TextBox}">
<Setter Property="AcceptsReturn" Value="True" />
<Setter Property="AllowDrop" Value="True" />
...
<Setter Property="Margin" Value="4,75,0,0" />
</Style>
If style define the key, it will only apply to the control that it explicitly indicate. Example:
<Style x:Key="TextBoxOneStyle" TargetType="{x:Type TextBox}">
<Setter Property="AcceptsReturn" Value="False" />
<Setter Property="AllowDrop" Value="True" />
...
<Setter Property="Margin" Value="4,0,0,0" />
</Style>
<Style x:Key="TextBoxTwoStyle" TargetType="{x:Type TextBox}">
<Setter Property="AcceptsReturn" Value="True" />
<Setter Property="AllowDrop" Value="True" />
...
<Setter Property="Margin" Value="4,75,0,0" />
</Style>
Using:
<TextBox Name="TextBoxOne"
Style="{StaticResource TextBoxOneStyle}" />
<TextBox Name="TextBoxTwo"
Style="{StaticResource TextBoxTwoStyle}" />
You can also specify the event handler via EventSetter:
<Style TargetType="{x:Type TextBox}">
<EventSetter Event="PreviewDragEnter" Handler="DropText_PreviewDragEnter" />
</Style>
Please see this link, for more information:
Styling and Templating MSDN

Using styles within a data template

I have a class called item, and it contains just two properties. I will display them on the screen as buttons with a style. This question relates to how I can style the button based on the IsSelected value, when the element I want to affect is in the style not the data template. I have already tried with a Trigger but been unable to get it to work.
The class is below.
public class Item : ObservableObject
{
private string _title;
private bool _isSelected;
public string Title
{
get { return _title; }
set
{
_title = value;
RaisePropertyChanged("Title");
}
}
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
I use a data template to display these items in a ItemsControls.
<ItemsControl ItemsSource="{Binding Path=Items}" ItemTemplate="{StaticResource ResourceKey=ItemTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Using the following style and data template.
<Style x:Key="ItemButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="ButtonBorder" BorderThickness="2,2,2,0" BorderBrush="#AAAAAA" CornerRadius="6,6,0,0" Margin="2,20,0,0" Background="Black">
<ContentPresenter
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="ItemTemplate">
<Button Height="60" Style="{StaticResource ItemButton}" Name="Button">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Title}"
HorizontalAlignment="Left" Margin="5,5,5,3" FontSize="25" Foreground="#6B6B6B" FontFamily="Arial" />
<Button Style="{StaticResource NoChromeButton}" Margin="0,0,5,0">
<Button.Content>
<Image Height="20" Source="/WpfApplication1;component/Image/dialogCloseButton.png"></Image>
</Button.Content>
<Button.ToolTip>
Close
</Button.ToolTip>
</Button>
</StackPanel>
</Button>
</DataTemplate>
I need to change the Background of "ButtonBorder" from Black to White when IsSelected is True, on the object Item.
I have added in a Trigger in the Data Template
This does not work, I guess its because the style overrides the DataTemplate, thus the background stays white. Yet when i try to do a trigger in the style, I can't access the property IsSelected?
DataTemplate Trigger
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter TargetName="Button" Property="Background" Value="White"/>
</DataTrigger>
</DataTemplate.Triggers>
Style trigger
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
Am i missing something?
Make your ButtonBorder.Background be {TemplateBinding Background}, which means it will use whatever background color is assigned to the templated Button, then you can change your Button's background based on a Trigger
<Style x:Key="ItemButton" TargetType="Button">
<Setter Property="Background" Value="Black" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="ButtonBorder" Background="{TemplateBinding Background}" ... >
<ContentPresenter ... "/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SelectableItemButton" TargetType="Button" BasedOn="{StaticResource ItemButton}">
<Setter Property="Background" Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="ItemTemplate">
<Button Height="60" Style="{StaticResource SelectableItemButton}">
...
</Button>
</DataTemplate>
I'm also making a SelectableItemButton Style which inherits from ItemButton, and just implements the trigger
Shouldn't the target be "ButtonBorder" instead of "Button" in :
<Setter TargetName="Button"....
Also, to access the property IsSelected you need to set the TargetType in the style ....

DataTrigger on RadioButton IsChecked

I have a scenario where I need to hide some content based on whether a radio button is checked or unchecked. For some reason I can't get this to work the way I expect it to. The behavior is the opposite of what I expect. If I adjust my xaml to accomodate the actual behavior that I'm seeing it everything gets hidden.
Essentially what I have is two radio buttons labeled Fixed and Cycle. When Fixed is checked I want the textbox associated with Fixed to have a visible foreground and the textbox associated with Cycle to have a transparent foreground and vice-versa. What I'm seeing is the exact opposite.
Here's my trigger:
<Grid.Resources>
<Style TargetType="TextBox" x:Key="FixedModeStyle">
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
ElementName=rbtFixedMode}" Value="True" >
<Setter Property="Foreground"
Value="{DynamicResource My.Fonts.Global.LightForeground}" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox" x:Key="CycleModeStyle">
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
ElementName=rbtCycleMode}" Value="True" >
<Setter Property="Foreground"
Value="{DynamicResource My.Fonts.Global.LightForeground}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
Here's my radio buttons and associated textboxes:
<RadioButton x:Name="rbtFixedMode" Content="Fixed"
GroupName="AveragingMode"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}"
IsChecked="{Binding AveragingWindowMode,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={x:Static Processors:AveragingMode.Fixed}}" />
<DockPanel Grid.Row="1" IsEnabled="{Binding IsChecked, ElementName=rbtFixedMode}">
<TextBox x:Name="txtFixedIntervalLength"
Style="{StaticResource FixedModeStyle}" DockPanel.Dock="Left"
Text="{Binding AveragingWindowFixedLength}" />
</DockPanel>
<RadioButton x:Name="rbtCycleMode" Content="Cycle"
GroupName="AveragingMode" Grid.Row="2"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}"
IsChecked="{Binding AveragingWindowMode,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={x:Static Processors:AveragingMode.Cycles}}" />
<DockPanel Grid.Row="3" IsEnabled="{Binding IsChecked, ElementName=rbtCycleMode}">
<TextBox x:Name="txtCycleIntervalLength"
Style="{StaticResource CycleModeStyle}" DockPanel.Dock="Left"
Text="{Binding AveragingWindowCycleLength}"/>
<TextBlock x:Name="txbCycles" Text="Cycles" Margin="4,10"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}" />
</DockPanel>
Any ideas?
Just making the text transparent is a bad idea, the user will still be able to edit it while it is transparent. Besides that the code is obfuscated and redundant. Do not create two styles for a TextBox, both containing the same setters; create a base-style and use BasedOn for sub-styles.
Not quite sure where your code goes wrong, i would suggest you clean it up, maybe there is some logical error, also here is a working example:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Page.Resources>
</Page.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<RadioButton Name="rbCycle" GroupName="g1" Content="Cycle"/>
<RadioButton Name="rbFixed" GroupName="g1" Content="Fixed" Grid.Column="1"/>
<TextBox Grid.Row="1" Text="cycle box">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbCycle}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBox Grid.Row="1" Grid.Column="1" Text="fixed box">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbFixed}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ScrollViewer>
</Page>
If you're using binding to set the values of your radio buttons, don't use groups. If you're using groups, don't use binding. The two don't play well together.
That may not be the cause of what you're seeing. But I bet it is. And it's certainly interfering with your ability to diagnose the problem, because after you start clicking on buttons their binding doesn't work anymore.

Resources