I've got an issue with a custom WPF button - whenever I click on it, it receives a click event but does not seem to get toggled (does not stay down when I click on another button). I've tried everything I can think of and still can't get it to work.
One weird thing that I have noticed though is that when I put a breakpoint in the MouseDown handler and just hit F5 to continue at that point, the button gets toggled and stays down. This leads me to believe that this is some sort of focus issue?
<ToggleButton Name="ToggleButton" PreviewMouseDown="ToggleButton_MouseDown_1" IsThreeState="False">
<StackPanel Orientation="Vertical">
<Label Content="Single" FontSize="15" FontWeight="Medium"/>
<Label Content="Speaker"/>
</StackPanel>
</ToggleButton>
private void ToggleButton_MouseDown_1(object sender, MouseButtonEventArgs e)
{
ToggleButton.IsChecked = !ToggleButton.IsChecked;
}
private void ToggleButton_MouseDown_1(object sender, MouseButtonEventArgs e)
{
ToggleButton.IsChecked = !ToggleButton.IsChecked;
}
Help? :)
As #Nick said in his comment, just remove your event handler PreviewMouseDown="ToggleButton_MouseDown_1" completely and it should work just fine.
If this is not the case you must have some other code which is causing the issue.
It sounds like you want the functionality of a set of radio buttons, but the look of a bunch of toggle buttons. In cases like these, using the inherited Control.Template property is really handy:
In your page resources, you can add:
<Style TargetType="RadioButton">
<Setter Property="Template">
<Setter.Value>
<ContentTemplate>
<ToggleButton Content="{TemplateBinding Content}" IsChecked="{TemplateBinding IsChecked}"/>
</ContentTemplate>
</Setter.Value>
</Setter>
</Style>
And then in your code:
<RadioButton Content="MyContent" GroupName="MyGroup"/>
This should make an object that looks like a toggle button, but deselects when you select something from the same group, like a RadioButton. You can further modify the ToggleButton in the Template until you get the look that you want.
Related
First I've tried to implement a Click Event to my Textbox. Unfortunately, it doesn't work with XAML.
So, my plan is to add a Button and whenever you click this Button, the textfield below should change it's letter (back to 1).
My idea was to put the button over the first textbox and to hide it, so that you see the first textbox.
But, if I set the button as hidden, my function doesn't work anymore.
Is there a solution to hide the button, but, still keep the function for the second textbox?
Hidden means control is loaded, takes up space on the screen, but won't be operational(clickable), so it doesn't help you.
You could edit the button's ControlTemplate and make it a simple Grid with Transparent background, without the Hidden part of course.
And last thing, you could add MouseDown function on your TextBox so you won't need the button at all.
If you use bindings and commands you have two ways:
<Button Command="{Binding ClickCommand}">
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock Text="Some text"/>
</ControlTemplate>
</Button.Template>
</Button>
or
<TextBlock Text="Some text">
<TextBlock.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding ClickCommand}"/>
</TextBlock.InputBindings>
</TextBlock>
Got it!
.xaml:
<TextBox MinWidth="90" x:Name="txtBoden" TextChanged="TxtBoden_TextChanged"
PreviewMouseDown="txtBoden_MouseDown"></TextBox>
.cs:
public void txtBoden_MouseDown(object sender, MouseButtonEventArgs e)
{
txtFach.Text = "1";
}
Recently I had been looking for a way to make the tabs in a TabControl editable and came across This example on telerik's website. That did exactly what I wanted but it got me thinking about a similar usage for buttons. I was wondering if it would be possible to use something like that and make a button that would show a textbox instead of the content presenter when say, you right click the button? I tried to make something like this work but so far have only ended up with a blank button.
<Button x:Name="SB" Height="222" Width="222" Click="SB_Click">
<ContentControl.ContentTemplate>
<DataTemplate>
<local:SuperButton Content="{Binding Path=x, Mode=TwoWay}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</Button>
Where x is a string variable and using the code behind from the link above (with a class name change, of course).
edit: This button will be in an itemscontrol, so I don't think naming the inner elements in xaml will work, but I do like the ease of Wolfgang's answer.
The WPF Content Model is really flexible and allows literally anything inside anything.
This is perfectly valid XAML:
<Button>
<TextBox/>
</Button>
Or even:
<Button>
<MediaElement Source="C:\Videos\WildLife.wmv"/>
</Button>
You can simply host a (e.g.) label (TextBlock) with the text AND a TextBox inside the Button and set their Visiblity properties.
That way, if you right click the button, the TextBox shows up.
<Button>
<Grid>
<TextBox Text=normal button caption" x:Name="label" />
<TextBox
x:Name="textbox"
Text="visible on right click"
MouseRightButtonDown="HandleRightClick"/>
</Grid>
</Button>
And then in your C# code create an event handler to set the Visiblity correctly.
void HandleRightClick(object sender, MouseButtonEventArgs e)
{
label.Visibility = Visibility.Collapsed;
textBlock.Visibility = Visibility.Visible;
}
I am new to WPF/XAML so please bear with the noob question.
I have designed a control panel that will eventually function as a backend for my website, and have just finished laying out all the buttons in tabs using TabControl element. (this is designed using the Visual Studio 'Window' forms.
My question is, is it possible to create a function in the xaml.cs file that will dynamically handle a specific event for all my button elements ? for example...
I have 30+ buttons and dont want 30 different Click="btnCustomers_click" + their respective functions in the c# code. What I desire is say one function that would allow me to click any button and then open a new window depending on which button was selected.
The below code is my current design however for 30+ buttons their will be alot of functions and it will be messy, hence my desire to have one function control which window is opened depending on which button is clicked.
private void btnMerchants_click(object sender, RoutedEventArgs e)
{
var newWindow = new frmMerchants();
newWindow.Show();
}
Thanks in advance for any advice given!! :)
You could use a style for this:
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="btnMerchants_click"/>
</Style>
If you set this up in the resources somewhere without an x:Key it will apply to all buttons.
e.g. if you have a Grid and you want a certain style to apply to all Buttons in it you would define it like this:
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="Button_Click"/>
</Style>
</Grid.Resources>
<Grid.Children>
<!-- Buttons and stuff -->
</Grid.Children>
</Grid>
If you just want to apply it to some buttons set the x:Key and reference the style:
<Grid>
<Grid.Resources>
<Style x:Key="AttachClickHandlerStyle" TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="Button_Click"/>
</Style>
</Grid.Resources>
<Grid.Children>
<Button Content="Click me!" Style="{StaticResource AttachClickHandlerStyle}"/>
<Button Content="Click me, too!" Style="{StaticResource AttachClickHandlerStyle}"/>
<Button Content="Something different." Click="SomeOtherButton_Click"/>
</Grid.Children>
</Grid>
In general you should refactor any attributes that occur more than once into a style to prevent duplicate code.
Also, since you are a beginner the following articles might be of interest:
Styling and Templating
Resources Overview
You can use routed events on the parent container.
Example:
<Grid Button.Click="GeneralHandler">
<!-- Some stuff -->
</Grid>
In the code behind:
public void GeneralHandler(object sender, RoutedEventArgs e)
{
Button b = e.OriginalSource as Button;
//<-- Do something
}
You can read more about it on MSDN.
Just assign the exact same Click="btnCustomers_click" handler (with a general function name) to all the buttons. Then in the function open the correct window based on the sender's Name.
I'm trying to implement "Mega Menu" style menus using WPF. To see examples of mega menus in web design, see here.
So far, I've tried creating a similar interface by using TextBlocks as the highest level of the menu, and then using the mouse hover event to display an additional window that appears positioned below the text block. This is cumbersome and inflexible, future changes would require adding/removing TextBlocks dynamically.
I have considered using the WPF Menu control, because I know the styles can be dramatically modified, but I haven't seen any way to produce multi-column layouts with the hierarchical model that the Menu control uses.
Is there a better way to do this? Am I going to have to stick with custom windows and relative positioning? Can someone point me to an example of this that has already been implemented?
Instead of using custom Windows and positioning, you could use a Popup control. Your can use the StaysOpen=false setting to have it close when the user clicks off-screen.
If you can settle for clicking a menu item instead of hovering, the following custom control will work:
[TemplatePart(Name="PART_HoverArea", Type=typeof(FrameworkElement))]
[TemplatePart(Name="PART_Popup", Type=typeof(Popup))]
public class MegaMenuItem : HeaderedContentControl
{
private FrameworkElement hoverArea;
private Popup popup;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Unhook old template
if (hoverArea != null)
{
hoverArea.PreviewMouseUp -= ShowPopupOnMouseDown;
}
hoverArea = null;
popup = null;
if (Template == null)
return;
// Hook up new template
hoverArea = (FrameworkElement)Template.FindName("PART_HoverArea", this);
popup = (Popup)Template.FindName("PART_Popup", this);
if (hoverArea == null || popup == null)
return;
hoverArea.PreviewMouseUp += ShowPopupOnMouseDown;
}
private void ShowPopupOnMouseDown(object sender, MouseEventArgs e)
{
popup.PlacementTarget = hoverArea;
popup.Placement = PlacementMode.Bottom;
popup.StaysOpen = false;
popup.IsOpen = true;
}
}
You would need a style to display it - something like this. Note the PART_ template part names:
<Style TargetType="WpfApplication14:MegaMenuItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="WpfApplication14:MegaMenuItem">
<Grid>
<Border Name="PART_HoverArea" Background="#fb9c3b" BorderBrush="White" BorderThickness="0,0,1,0">
<ContentPresenter Content="{TemplateBinding Header}" />
</Border>
<Popup
Name="PART_Popup"
PlacementTarget="{Binding ElementName=HoverArea}"
>
<Border MinWidth="100" MaxWidth="400" MinHeight="40" MaxHeight="200" Background="#0d81c3">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The XAML for your menu would then be:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<WpfApplication14:MegaMenuItem Header="Parent 1">
<WrapPanel Margin="5">
<TextBlock Text="Put any content you want here" Margin="5" />
<TextBlock Text="Put any content you want here" Margin="5" />
<TextBlock Text="Put any content you want here" Margin="5" />
</WrapPanel>
</WpfApplication14:MegaMenuItem>
<WpfApplication14:MegaMenuItem Header="Parent 2">
<WrapPanel Margin="5">
<TextBlock Text="Put any content you want here" Margin="5" />
<TextBlock Text="Put any content you want here" Margin="5" />
<TextBlock Text="Put any content you want here" Margin="5" />
</WrapPanel>
</WpfApplication14:MegaMenuItem>
</StackPanel>
Making the menu appear on hover is much harder, because of the way Popups steal focus (you can show the menu, but you can't easily hide it if they mouse over another menu). For that a custom window might work better.
You could use a HeaderedItemsControl and swap out the Panel to suit your needs; by default it uses a StackPanel however a WrapPanel may suit you better. The pop out and mouse over behavior do not exist by default and would need to be implemented.
A more robust approach would be to leverage a custom Expander; as it provides the pop out behavior you are after and the linked to walkthrough provides the mouse over behavior.
I wonder if the Ribbon control can be retrofitted to do this? It provides tabs, labels, columns and all that.
Please use this UI design sparingly and make sure that it only opens and closes when the user specifically requests such. It's tremendously annoying when a popup mega-menu appears over a website I'm viewing, and I can't get it to close, except for when I want to click on it and it goes away.
Custom windows and relative position are essentially how the WPF Menu/MenuItem control works... but as you've found, it's non-trivial. Best bet would be to retemplate the Menu/MenuItem controls to meet your need.
How to set the focus on an TextBox element in WPF
I have this code:
txtCompanyID.Focusable = true;
txtCompanyID.Focus();
...but it is not working.
Any idea?
In XAML:
<StackPanel FocusManager.FocusedElement="{Binding ElementName=Box}">
<TextBox Name="Box" />
</StackPanel>
Nobody explained so far why the code in the question doesn't work. My guess is that the code was placed in the constructor of the Window. But at this time it's too early to set the focus. It has to be done once the Window is ready for interaction. The best place for the code is the Loaded event:
public KonsoleWindow() {
public TestWindow() {
InitializeComponent();
Loaded += TestWindow_Loaded;
}
private void TestWindow_Loaded(object sender, RoutedEventArgs e) {
txtCompanyID.Focus();
}
}
try FocusManager.SetFocusedElement
FocusManager.SetFocusedElement(parentElement, txtCompanyID)
txtCompanyID.Focusable = true;
Keyboard.Focus(txtCompanyID);
msdn:
There can be only one element on the
whole desktop that has keyboard focus.
In WPF, the element that has keyboard
focus will have IsKeyboardFocused set
to true.
You could break after the setting line and check the value of IsKeyboardFocused property. Also check if you really reach that line or maybe you set some other element to get focus after that.
Try this : MyTextBox.Focus ( );
None of this worked for me as I was using a grid rather than a StackPanel.
I finally found this example:
http://spin.atomicobject.com/2013/03/06/xaml-wpf-textbox-focus/
and modified it to this:
In the 'Resources' section:
<Style x:Key="FocusTextBox" TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=textBoxName, Path=IsVisible}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=textBoxName}"/>
</DataTrigger>
</Style.Triggers>
</Style>
In my grid definition:
<Grid Style="{StaticResource FocusTextBox}" />
In case you haven't found the solution on the other answers, that's how I solved the issue.
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
TEXTBOX_OBJECT.Focus();
}), System.Windows.Threading.DispatcherPriority.Render);
From what I understand the other solutions may not work because the call to Focus() is invoked before the application has rendered the other components.
In Code behind you can achieve it only by doing this.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
txtIndex.Focusable = true;
txtIndex.Focus();
}
Note: It wont work before window is loaded
Another possible solution is to use FocusBehavior provided by free DevExpress MVVM Framework:
<TextBox Text="This control is focused on startup">
<dxmvvm:Interaction.Behaviors>
<dxmvvm:FocusBehavior/>
</dxmvvm:Interaction.Behaviors>
</TextBox>
It allows you to focus a control when it's loaded, when a certain event is raised or a property is changed.