I am working on a WPF Xaml application. The app has various stackpanels (that behave like icons) that I need to change the Visibility based on certain criteria.
Question:
How can I collapse all child elements (stackpanels)?
I am collapsing each one by one in the backend in vb.net. But much rather find a cool way to do it all at once.
In that case you can have two options
you can achieve it through style(This will not work if your following MVVM, that is if your binding)
Create coustom control
With Style:
Write the style as below with the target type which is used to display the image
<Window.Resources>
<Style TargetType="TextBox">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox Height="26" Width="200" Name="text1"/>
<TextBox Height="26" Width="200" Name="text2"/>
<Button Height="26" Width="200" Click="Button_Click_2" />
</StackPanel>
</Grid>
TextBox by default will be collapsed you can make it visible based on the search in the backend code
Custom control:
This will be just a wrapper for what ever control your using to display the icon but with only one change is that the default visibility will be collapsed. Then you can make it visible which ever you want
Override hide the already existing Visibility the property with the default value collapsed
You can set the visibility to parent instead of setting it to each control
For example
<StackPanel>
<StackPanel Name="pane1">
<Button Height="30" Width="200" Content="one" Click="Button_Click" />
</StackPanel>
<StackPanel Name="panel2">
<Button Height="30" Width="200" Content="two" Click="Button_Click_1" />
</StackPanel>
</StackPanel>
In you back end write the logic to set the visibility for stackpanel instead of each control
private void Button_Click(object sender, RoutedEventArgs e)
{
pane1.Visibility = Visibility.Collapsed;
panel2.Visibility = Visibility.Visible;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
panel2.Visibility = Visibility.Collapsed;
pane1.Visibility = Visibility.Visible;
}
If your following mvvm then bind to the visibility property of the stack panel like below
<StackPanel>
<StackPanel Visibility="{Binding CanShowPanel1}">
<Button Height="30" Width="200" Content="one" Click="Button_Click" />
</StackPanel>
<StackPanel Visibility="{Binding CanShowPanel2}">
<Button Height="30" Width="200" Content="two" Click="Button_Click_1" />
</StackPanel>
</StackPanel>
Bind them using an IValueConverter implementation like BooleanToVisibilityConverter.
If that isn't good enough, you will have to do them one by one. Maybe write a custom behavior?
The easiest way to do that is to use IValueConverter with parameter.
<StackPanel>
<StackPanel Visibility="{Binding TheQuery,Converter={StaticResource QueryConverter,ConverterParameter="MyFirstStackPanelVisible"}}">
</StackPanel>
<StackPanel Visibility="{Binding TheQuery,Converter={StaticResource QueryConverter,ConverterParameter="MySecondStackPanelVisible"}}">
</StackPanel>
</StackPanel>
public class QueryConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch((string)parameter)
{
case "MyFirstStackPanelVisible"
bool result =CheckQueryCriteriaForFirstStackPanel();
return Visibility.Visible or Visibility.Collapsed;
case "MySecondStackPanelVisible"
bool result =CheckQueryCriteriaForSecondStackPanel();
return Visibility.Visible or Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Of course you shouldn't make CheckQueryCriteriaFor... function for every case.
This approach guarantee logic to be in one place.
Related
Starting with a Grouped Items Page template, I want to be able to perform tasks on the grid items when they are clicked. Namely, I want to change the background image, and add/remove the underlying object to a list of selected items.
Here's my DataTemplate:
<GridView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="LightGray" BorderThickness="2" Margin="0,0,20,20">
<Grid HorizontalAlignment="Left" Width="390" Height="190">
<Grid.Background>
<ImageBrush ImageSource="/Assets/unselected.png" Stretch="None"/>
</Grid.Background>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Image VerticalAlignment="Top" Stretch="None" Source="{Binding ImageUrl}" Margin="10,10,0,0"/>
<StackPanel MaxWidth="270">
<TextBlock Text="{Binding Summary}"/>
<TextBlock Text="{Binding Brand}" />
<TextBlock Text="{Binding Detail}" TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
OnTap, I want to togle the ImageSource value of the Grid.Background from unselected.png to selected.png. This I believe I can do using VisualStates and Storyboards, but I've been unable to get this to work in the past (I'll spare you the chaos of my attempts in xaml).
Needless to say, I've tried following the steps detailed here using Blend, but the Grid.Background property doesn't seems to be state specific. If I try changing the background brush in the Pressed or Selected states, it also changes for the Normal state.
Since I want to grab the data context of the selected item and add/remove it from a list, should I just be handling all this together in an OnTap event handler? I would prefer to keep these concerns separated, but I'll do what I need to...
thanks!
One clean way to do this would be engage the selection method (Tap) in such a way that it only opperates on its items, and the items themselves have properties which Implement the INotifyPropertyChanged interface
Your View Model would have a collection of your custom objects that have properties that can notify the ui
public class MyObject : INotifyPropertyChanged
{
private string _summary;
public string summary
{
get {return _summary}
set
{
_summary = value;
OnPropertyChanged()
}
}
//Other Properties: brand || detail
private ImageSource _backgroundImage;
public ImageSource backgroundImage
{
get {return _backgroundImage}
set
{
_backgroundImage = value;
OnPropertyChanged()
}
}
private bool _IsSelected;
public bool IsSelected
{
get {return _IsSelected;}
set
{
_IsSelected = value;
OnPropertyChanged()
}
}
}
Then although your code behind can be used to change the value of IsSelected, or Background image ... if you choose to go with IsSelected, you can still separate your concerns by not directly setting the resource of the background image in code behind. The Codebehind will only iterate over the items to toggle the IsSelected property, and you can use xaml to define the image that the background should use by creating a custom converter.
public class MyCustomControlOrPage.cs : UserControl //Or ApplicationPage
{
//.......code
protected void HandleTap(object sender, GestureEventArgs e)
{
foreach(var item in ((Listbox)sender).ItemsSource)
{
((MyObject)item.IsSelected = (MyObject)item.Name == (e.NewItems[0] as MyObject).Name? true: false;
}
}
}
then the converter
public class BackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ImageSource source = value == true ? new BitmapImage(uriForSelected) : new BitmapImage(uriForunselected);
return source;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
BitmapImage thisValue = value as BitmapImage;
return thisValue;
}
}
and FINALLY the XAML where the grid background binds to the IsSelected property and allows the converter to transform the bool to an ImageSource of type BitmapImage:
//add xmlns:Converters=clr-namesapce:Yournamespace.UpTo.TheNamespaceBackgroundConverterIsIn" to the page or control definition
<UserControl.Resources>
<Converters:BackgroundConverter x:key="BgSourceConverter" />
</UserControl.Resources>
<GridView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="LightGray" BorderThickness="2" Margin="0,0,20,20">
<Grid HorizontalAlignment="Left" Width="390" Height="190">
<Grid.Background>
<ImageBrush ImageSource="{Binding Path=IsSelected, Mode=TwoWay, Converter={Binding Source={StaticResource BGSourceConverter}}}" Stretch="None"/>
</Grid.Background>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Image VerticalAlignment="Top" Stretch="None" Source="{Binding ImageUrl}" Margin="10,10,0,0"/>
<StackPanel MaxWidth="270">
<TextBlock Text="{Binding Summary}"/>
<TextBlock Text="{Binding Brand}" />
<TextBlock Text="{Binding Detail}" TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
I have 4 expander controls.
When one expander is expanded, how can I make all others collapse/close?
Try out following code:
XAML:
<StackPanel Name="StackPanel1">
<StackPanel.Resources>
<local:ExpanderToBooleanConverter x:Key="ExpanderToBooleanConverter" />
</StackPanel.Resources>
<Expander Header="Expander 1"
IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=1}">
<TextBlock>Expander 1</TextBlock>
</Expander>
<Expander Header="Expander 2"
IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=2}">
<TextBlock>Expander 2</TextBlock>
</Expander>
<Expander Header="Expander 3"
IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=3}">
<TextBlock>Expander 3</TextBlock>
</Expander>
<Expander Header="Expander 4"
IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=4}">
<TextBlock>Expander 4</TextBlock>
</Expander>
</StackPanel>
Converter:
public class ExpanderToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value == parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (System.Convert.ToBoolean(value)) return parameter;
return null;
}
}
ViewModel:
public class ExpanderListViewModel
{
public Object SelectedExpander { get; set; }
}
Initialization
StackPanel1.DataContext = new ExpanderListViewModel();
Explanation:
In XAML we have 4 expanders. They all inherit a ViewModel (of type ExpanderListViewModel) from container StackPanel through DataContext.
They all bind to single property on ViewModel class. And have defined a unique index for themselves using ConverterParameter in binding. That index gets saved in SelectedExpander property whenever you expand an expander. And using that index, the Converter returns true if the stored index matches with given index and false if stored index does not match.
Put a breakpoint in Convert and ConvertBack methods of Converter class and you will see what is going on.
this is how I did it:
1) added a StackPanel and MUST add a name tag attribute (as this is the master).
StackPanel Name="StackPanel1"
2) add as many Expanders as you need (1 to 100's if needed) each MUST have:-
Expanded="Expander_Expanded"
added (notice all have 100% the same wording).
3) no other details need to match on each ( no height's names etc.. needed).
Xaml:
<StackPanel Name="StackPanel1">
<Expander Header="Expander 1" Expanded="Expander_Expanded">
<TextBlock>Expander 1</TextBlock>
</Expander>
<Expander Header="Expander 2" Expanded="Expander_Expanded">
<TextBlock>Expander 2</TextBlock>
</Expander>
<Expander Header="Expander 3" Expanded="Expander_Expanded" >
<TextBlock>Expander 3</TextBlock>
</Expander>
<Expander Header="Expander 4" Expanded="Expander_Expanded" >
<TextBlock>Expander 4</TextBlock>
</Expander>
4) To control the open/close of all "Expanders" on the named "StackPanel1" StackPanel you only need to add the below code once.
VB code-behind:
Private Sub Expander_Expanded(sender As Object, e As RoutedEventArgs)
For Each exp As Expander In StackPanel1.Children
If exp IsNot sender Then
exp.IsExpanded = False
End If
Next
End Sub
5)Now you can change/add what content, button's, textbox's etc.. you need just do not change 2 things 1, "StackPanel Name" 2, "Expander Expanded" without updating the code-behind else things will not work.
Hope this information is helpful to you.
What's happening?
1) All panels are parents and all controls on that panel are children,
2) All controls are children of a parent panel.
3) A class deals with one call at a time.
4) The class deals with child.
6) The class move to next child.
7) Stops once all children have been asked.
So the pseudo code is like this:
1) Listen for a child’s named x
2) Ask each child in parents list of children
3) If child is not calling then
4) Child is expanded is false
5) End asking that child
6) Move to next child and ask again
7) Until all children have been asked
Just setting the Lost focus seems to be the easiest way to do this.
Xaml:
<Expander LostFocus="CollapseExpander" ExpandDirection="Down" Width="175">
<ListBox Height="265" Margin="0,5,0,10">
</ListBox>
</Expander>
VB:
Private Sub CollapseExpander(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
sender.IsExpanded = False
End Sub
Use MVVM and bind the IsExpanded property to a boolean flag on your view models. When one is updated to true, set all the others to false.
#wassim-azirar asked to the accepted answer:
How can I expand 'Expander 1' at the application Startup ?
I added in the ViewModel:
SelectedExpander = "1";
Because of the fact, that the "1" is not the same object as the "1" in XAML this will not work, so I changed decyclone's answer like this:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (string)value == (string)parameter;
}
The answer of decyclone was very helpful for me - Thanks.
So I would like to share my experience if someone needs it.
Try the Accordion control from WPF Toolkit - February 2010 Release
http://www.dotnetspark.com/kb/1931-accordion-wpf-toolkit-tutorial.aspx
Sample code:
<my:Accordion x:Name="accordion1" VerticalAlignment="Top" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" SelectionMode="ZeroOrOne">
<my:AccordionItem Header="First Header" Content="First Content"/>
<my:AccordionItem Header="Second Header">
<StackPanel Height="300">
<TextBlock Text="Second Content" /></StackPanel>
</my:AccordionItem>
<my:AccordionItem>
<my:AccordionItem.Header>
<TextBox Text="Third Item" />
</my:AccordionItem.Header>
<StackPanel Height="300">
<TextBlock Text="Third Item" />
</StackPanel>
</my:AccordionItem>
<my:AccordionItem>
<my:AccordionItem.Header>
<TextBlock Text="Fourth Item" />
</my:AccordionItem.Header>
<StackPanel Height="300">
<TextBlock Text="Third Item" />
</StackPanel>
</my:AccordionItem>
</my:Accordion>
I also needed this, but all answers was too much work IMO.
Here is how I did it:
added StackPanel (child align is set to vertical).
added 3 Expanders into it. (needed 3)
set height of Expanders to 120px to add elements to it.
each Expander called ex1..3.
each one got 2 events
private void ex1_Collapsed(object sender, RoutedEventArgs e)
{
ex1.Height = 23.0;
}
private void ex1_Expanded(object sender, RoutedEventArgs e)
{
ex1.Height = 120.0;
ex2.IsExpanded = false;
ex3.IsExpanded = false;
}
reset all the Expanders that should be collapsed height back to 23px at window_loaded.
that it.
I have a list of expanders which I want to control its expanded state(IsExpanded) with global toggle button which should toggle between expanded/collapsed state.
The solution which I have got so far does that by binding the expander's IsExpanded state to the togglebutton's IsChecked state. This works as long as I dont manually dont toggle the expanders. Once I do that those particular expanders dont respect the binding (toggle button's IsChecked state).
Any idea why? and is there a clean solution in XAML for this?
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel>
<ToggleButton Name="ExpandAll">Toggle</ToggleButton>
<Expander IsExpanded="{Binding ElementName=ExpandAll,Path=IsChecked, Mode=OneWay}">
Hai
</Expander>
<Expander IsExpanded="{Binding ElementName=ExpandAll,Path=IsChecked, Mode=OneWay}">
Hello
</Expander>
<Expander IsExpanded="{Binding ElementName=ExpandAll,Path=IsChecked, Mode=OneWay}">
Weird
</Expander>
</StackPanel>
</Grid>
</Page>
I know that this post is very old. Just posting this for anyone else who comes across. The below code worked for me.
<Expander IsExpanded="{Binding ElementName=ExpandAll, Path=IsChecked, UpdateSourceTrigger=Explicit}">
</Expander>
This works when the expanders are generated dynamically, for example inside a DataGrid.RowDetailsTemplate.
I don't think you can achieve this entirely in XAML, but the following allows you to do it with an IValueConverter:
<StackPanel>
<StackPanel.Resources>
<local:Converter x:Key="Converter" />
</StackPanel.Resources>
<ToggleButton Name="ExpandAll">
<ToggleButton.IsChecked>
<MultiBinding Mode="OneWayToSource" Converter="{StaticResource Converter}">
<Binding ElementName="Expander1" Path="IsExpanded" />
<Binding ElementName="Expander2" Path="IsExpanded" />
<Binding ElementName="Expander3" Path="IsExpanded" />
</MultiBinding>
</ToggleButton.IsChecked>
Toggle</ToggleButton>
<Expander Name="Expander1">
Hai
</Expander>
<Expander Name="Expander2">
Hello
</Expander>
<Expander Name="Expander3">
Weird
</Expander>
</StackPanel>
And your Converter is as below:
public class Converter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//we're using OneWayToSource, so this will never be used.
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
// we want to convert the single 'IsChecked' value from the ToggleButton into
// 3 'IsExpanded' values
var allValues = new object[targetTypes.Length];
for (int i = 0; i < allValues.Length; i++)
{
allValues[i] = value;
}
return allValues;
}
}
This works by setting up a OneWayToSource binding between the IsChecked property of the ToggleButton (i.e. the binding will be set against the source when the target value changes), and uses an IMultiValueConverter to translate the single value into one for each of the Expanders.
I've been struggling with this for quite some time and I can't seem to find a proper solution. This is the scenario stripped down. Imagine you have the following XAML:
<Grid x:Name="LayoutRoot" Background="White">
<Grid x:Name="Host" Width="200" Height="200">
<Popup IsOpen="True">
<Button Content="Some Button" Click="Button_Click" />
</Popup>
</Grid>
</Grid>
In the Button_Click event handler all I do is collapse the grid with name Host.
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Host.Visibility = System.Windows.Visibility.Collapsed;
}
What I expected was that the Popup would close therefore hiding the Button. I understand that Popups are not in the same VisualTree and I understand why this might not be working the way I expect it to, but there should be some kind of mechanism for this to happen automatically. The only workaround that comes to my mind is on LayoutUpdated to traverse the visual tree up and ask each Button's parent if it is visible and if I meet a collapsed parent -> close the Popup. However, imagine the performance hit having a HUGE visual tree. It's insane to traverse the visual tree on every layout pass.
I'm open to any sort of suggestions.
EDIT: It seems that I did not explain fully my scenario. The case is to collapse the Popup if ANY of its parent gets collapsed (not just the immediate one). In WPF there is a useful property called IsVisible which is different than Visibility. For example, Visibility might still be Visible, but IsVisible will be false in this scenario.
Best Regards,
K
I think you found a bug, or at least a "weirdness" in the popup control - check this out:
My initial thought was to simply Bind the Visibility of the Popup to the Host. This SHOULD work.
<Grid x:Name="LayoutRoot" Background="White">
<Grid x:Name="Host" Width="200" Height="200" Background="Aqua">
<Popup IsOpen="True" Visibility="{Binding ElementName=Host, Path=Visibility}" Height="100" Width="100">
<Button Content="Some Button" Click="Button_Click"/>
</Popup>
</Grid>
</Grid>
But it does not work. The "Host" grid disappears, but I still see the button. This confused me, so I fired up Silverlight Spy, and check this out - setting the Visibility of the Popup does NOT hide the button!
See Demo Video
Anyway, in order to make this work, you just need to massage things a little bit in order tie the Host Visibility to the IsOpen property. I used a converter here:
<UserControl.Resources>
<Junk:VisibilityToBoolConverter x:Key="VisibilityToBoolConverter"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid x:Name="Host" Width="200" Height="200" Background="Aqua">
<Popup IsOpen="{Binding ElementName=Host, Path=Visibility, Converter={StaticResource VisibilityToBoolConverter}}" Height="100" Width="100">
<Button Content="Some Button" Click="Button_Click"/>
</Popup>
</Grid>
</Grid>
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Host.Visibility = System.Windows.Visibility.Collapsed;
}
public class VisibilityToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((Visibility) value) == Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
That's working for me.
If you just want to close the popup, why don't you set the IsOpen at the popup to false.
<Grid x:Name="LayoutRoot" Background="White">
<Grid x:Name="Host" Width="200" Height="200">
<Popup x:Name="HostPopup" IsOpen="True">
<Button Content="Some Button" Click="Button_Click" />
</Popup>
</Grid>
</Grid>
private void Button_Click(object sender, RoutedEventArgs e)
{
this.HostPopup.IsOpen = false;
}
This closes the popup.
I have a ToggleButton that is malfunctioning. As I understand it, a ToggleButton should go checked when clicked then unchecked when clicked again.
The ToggleButton in this example does not. Clicking it just sets it to checked again. Any Ideas why?
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ToggleButton Width="100" Height="35" Name="btnAddLinkComment" >
<CheckBox Content=" Comment" FlowDirection="RightToLeft" IsHitTestVisible="False"
Focusable="False" IsChecked="{Binding ElementName=txtLinkComment, Path=Text}"
Name="chkHasComment" Margin="5"/>
</ToggleButton>
<Popup IsOpen="{Binding ElementName=btnAddLinkComment,Path=IsChecked}"
PlacementTarget="{Binding ElementName=btnAddLinkComment}" Name="popAddCommentLink"
AllowsTransparency="True" StaysOpen="False" PopupAnimation="Fade" HorizontalOffset="-50"
VerticalOffset="50">
<Border BorderBrush="#FF000000" Background="LightBlue" BorderThickness="1,1,1,1"
CornerRadius="8,8,8,8" Padding="5">
<Grid Background="LightBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock TextWrapping="Wrap" Foreground="Black">Enter Link Comment:</TextBlock>
<TextBox Grid.Column="1" Name="txtLinkComment" Width="200"></TextBox>
</Grid>
</Border>
</Popup>
</Grid>
</Page>
I guess this happens due to popup being bent to the btnAddLinkComment.isChecked property. I believe what happens is that you're clicking on the button when pop is shown which makes it to close and sets button's IsChecked field to false which puts the button into untoggled state; then the click gets processed by the button itself and since it not toggled it becomes toggled and popup gets shown again. I guess you could resolve the issue by removing the binding and do some handling in code; smth like this:
btnAddLinkComment.Click += btnAddLinkComment_Click;
popAddCommentLink.Closed += popAddCommentLink_Closed;
private void btnAddLinkComment_Click(object sender, RoutedEventArgs e)
{
if (popAddCommentLink.IsOpen && btnAddLinkComment.IsChecked == false)
popAddCommentLink.IsOpen = false;
else if (!popAddCommentLink.IsOpen && btnAddLinkComment.IsChecked == true)
popAddCommentLink.IsOpen = true;
}
private void popAddCommentLink_Closed(object sender, EventArgs e)
{
btnAddLinkComment.IsChecked = false;
}
hope this helps, regards
I am not entirely sure what you want to accomplish but the code below might be a step in the right direction. Please elaborate!
<Window x:Class="ToggleButtonSpike.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
xmlns:local="clr-namespace:ToggleButtonSpike">
<Window.Resources>
<local:TextToBool x:Key="StringToBool"/>
</Window.Resources>
<StackPanel>
<ToggleButton Name="Toggle" >
<CheckBox IsHitTestVisible="False"
Content="{Binding ElementName=Comment, Path=Text,
UpdateSourceTrigger=PropertyChanged}"
IsChecked="{Binding ElementName=Comment, Path=Text,
Converter={StaticResource StringToBool}}"/>
</ToggleButton>
<Popup IsOpen="{Binding ElementName=Toggle, Path=IsChecked}"
PlacementTarget="{Binding ElementName=Toggle}">
<StackPanel>
<TextBlock Foreground="White">
Enter comment:
</TextBlock>
<TextBox Name="Comment"/>
</StackPanel>
</Popup>
</StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Data;
namespace ToggleButtonSpike
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
public class TextToBool : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return !string.IsNullOrEmpty((string)value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}
When you click on toggle button. It will checked or unchecked, please kindly remember that. At the first click on it, it will be focused.
Please try:
<ToggleButton Focusable="False"/>
Hope to help you