WPF- How to hide a dropdown menu after click - c#

I have a SplitButton in my WPF window, which is borrowed from Xceed's Extended WPF Toolkit. Its dropdown content is consisted of some RadioButtons. Something like:
<Window x:Class="WpfTest.Test3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tk="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
Title="Test3" Height="300" Width="300">
<Grid Height="25" Width="150">
<tk:SplitButton Content="Default Command">
<tk:SplitButton.DropDownContent>
<StackPanel>
<RadioButton Content="Default Command" GroupName="variations" Margin="5" IsChecked="True"/>
<RadioButton Content="Alternate Command 1" GroupName="variations" Margin="5"/>
<RadioButton Content="Alternate Command 2" GroupName="variations" Margin="5"/>
</StackPanel>
</tk:SplitButton.DropDownContent>
</tk:SplitButton>
</Grid>
</Window>
which generates something like this:
The problem is, when I click on each of the RadioButtons the dropdown menu doesn't dissappear. I did some googling and realized that I should handle the Click event for each RadioButton. But I don't know how to hide the dropdown menu in that event handler. As a side-note, it seems a MenuItem has the property of StaysOpenOnClick, but there is no such thing for other controls.
Although doing this programmatically would suffice, but is there an MVVM way for this?

Add Checked event on your radio button and use SplitoButton.IsOpen=false;. Follow this code.
Xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tk="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
Title="MainWindow" Height="350" Width="525">
<Grid>
<tk:SplitButton Name="SplitButton" Content="Default Command">
<tk:SplitButton.DropDownContent>
<StackPanel>
<RadioButton Checked="rb_Checked" Content="Default Command" GroupName="variations" Margin="5" IsChecked="True"/>
<RadioButton Checked="rb_Checked" Content="Alternate Command 1" GroupName="variations" Margin="5"/>
<RadioButton Checked="rb_Checked" Content="Alternate Command 2" GroupName="variations" Margin="5"/>
</StackPanel>
</tk:SplitButton.DropDownContent>
</tk:SplitButton>
</Grid>
</Window>
.cs
private void rb_Checked(object sender, RoutedEventArgs e)
{
SplitButton.IsOpen = false;
}

Related

Setting a combobox to update a textbox in Visual Studio, c#, Microsoft Blend, XAML

I am switching over a program from Access to C# in visual studio 2015 using Microsoft Blend. In short I have a combobox labeled cb_Address. It is bound to a field called "address: from a database called "orderheader" in XAML via:
<ComboBox x:Name="cb_Address" HorizontalAlignment="Left" Margin="10,158.71,0,0" VerticalAlignment="Top" Width="90" IsEditable="True" ItemTemplate="{DynamicResource orderheaderTemplate}" ItemsSource="{Binding XPath=/dataroot/orderheader}">
That populates the address combo box (user can now use the dropdown menu to select a record, although it's populating the box with an incremental record value rather than the addy itself, I need to fix that later.) In the event that a user selects a record I'd like it to update a textbox on the same page called tb_Address with the address field from the orderheader db.
In access that would be something like:
Sub cb_Address_AfterUpdate()
On Error GoTo e1
DoCmd.ShowAllRecords
Me.RecordsetClone.FindFirst "[auto] = " & Me![cb_Address]
Me.Bookmark = Me.RecordsetClone.Bookmark
e1:
End Sub
As of yet I haven't found a clear tutorial on how to do the event handler with this Blend/c# environment. My best guess is to use SelectionChanged like
private void cb_Address_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
but being new to c# I haven't found the code to update the tb_Address textbox. I was playing around with
cb_AddressItem cbi = ((sender as cb_Address).SelectedItem as Lcb_AddressItem);
But I'm at a loss for how to continue. Any help is appreciated!
Edit 1: As per the suggestion below, I now have this heading my window XAML
<Window x:Class="CC_Ticketing_WPF.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:CC_Ticketing_WPF"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="800" Width="600">
and this as my combobox and text box respectively:
<ComboBox x:Name="cb_Address" HorizontalAlignment="Left" Margin="10,158.71,0,0" VerticalAlignment="Top" Width="90" IsEditable="True" ItemTemplate="{DynamicResource orderheaderTemplate1}" ItemsSource="{Binding XPath=/dataroot/orderheader}" SelectedValuePath="Content">
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="41,214,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="35.824" Width="154" FontSize="21.333" FontFamily="Adobe Arabic" Text="{Binding ElementName=cb_Address,Path=SelectedItem.Content,Mode=OneWay}">
Unfortunately selecting a record from the combo box still only populates itself with a numerical number and the textbox with nothing. I tried replacing "Content" with "address" in both snippits in case it the direct database label but that provided the same result.
EDIT 2:
The locations of any instance of "orderheaderTemplate."
in MainWindow.xaml, just under the xmlns declarations:
<Window.Resources>
<DataTemplate x:Key="orderheaderTemplate">
<StackPanel>
<TextBlock Text="{Binding XPath=address}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="orderheaderTemplate1">
<StackPanel>
<TextBlock Text="{Binding XPath=address}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
In App.xaml, just under the xmlns declarations:
<Application.Resources>
<XmlDataProvider x:Key="orderheaderDataSource" Source="C:\Users\User\Desktop\C#_Ticketing\orderheader.xml" d:IsDataSource="True"/>
</Application.Resources>
In the Resources window:
https://dl.dropboxusercontent.com/u/22083389/Xdata2.png
Edit 3
Recap: In the simplest terms: I created an xml data source in Visual Studio 2015 Blend. I named that xml Datasource orderheaderDatasource and linked it to my database which is in turn named orderheader. That xml orderheader database has many records, each with several fields like address, city, fname, lname, etc.
All I need to accomplish is for a combobox to populate itself with the address fields of every record, then when the user selects one, send that address field to a textbox.
The Entire clean slate Xaml at this point after backtracking:
<Window x:Class="CC_Ticketing_WPF.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:CC_Ticketing_WPF"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="800" Width="600">
<Window.Resources>
<XmlDataProvider x:Key="orderheaderDataSource" XPath="/Info">
<x:XData>
<Info xmlns="">
<Order ID="001" Address="Example 1" />
<Order ID="002" Address="Example 2" />
<Order ID="003" Address="Example 2" />
</Info>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<StackPanel>
<ComboBox x:Name="cb_Address" DataContext="{StaticResource orderheaderDataSource}" ItemsSource="{Binding XPath=Order}" DisplayMemberPath="#Address" HorizontalAlignment="Left" VerticalAlignment="Top" Width="90" IsEditable="True"/>
<TextBlock x:Name="tb_Address" Text="{Binding ElementName=cb_Address,Path=Text}"/>
</StackPanel>
</Window>
All this does currently is populate the combobox with
Example 1
Example 2
Example 3
and upon selecting it does send to the textbox.
Every effort to link the combobox to orderheader's "address" field then send it to the textbox has failed. I can get the combobox to populate the addresses from orderheader correctly with some of the early code, but that's it. Nothing has ever sent the address to the textbox upon selecting, which after a week of trying and Cadogi's good help has sent me spiraling into a void of insanity and disbelief in the wake of XAML's apparent hateful nature for first timers.
Final Edit | Working Code
<Window x:Class="CC_Ticketing_WPF.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:CC_Ticketing_WPF"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="600">
<Window.Resources>
<DataTemplate x:Key="orderheaderTemplate">
<StackPanel>
<TextBlock Text="{Binding XPath=address}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ComboBox x:Name="cb_Address" DataContext="{StaticResource orderheaderDataSource}" ItemsSource="{Binding XPath=/dataroot/orderheader/address}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="90" IsEditable="True"/>
<TextBlock x:Name="tb_Address" Text="{Binding ElementName=cb_Address,Path=Text}"/>
</StackPanel>
</Window>
I would just keep this in the XAML to keep it nice and clean-
in your combo box add SelectedValuePath property:
<ComboBox x:Name="cb_Address" HorizontalAlignment="Left" Margin="10,158.71,0,0" VerticalAlignment="Top" Width="90" IsEditable="True" ItemTemplate="{DynamicResource orderheaderTemplate}" ItemsSource="{Binding XPath=/dataroot/orderheader}" SelectedValuePath="Content" />
This should tell the combobox where to look when requesting a value.
in your textbox bind the Text to the combobox selected value:
<Textbox x:Name="tb_Address" Text="{Binding ElementName=cb_Address,Path=SelectedItem.Content,Mode=OneWay}" />
Edit below
Could you try the code below instead of what you have / or start a new project to test this. Ignore the DataContext just have this inside your initial grid.:
<ComboBox x:Name="cb_Address" HorizontalAlignment="Left" Margin="10,158.71,0,0" VerticalAlignment="Top" Width="90" IsEditable="True" SelectedValuePath="Content">
<ComboBoxItem Content="Address Example 1"/>
<ComboBoxItem Content="Address Example 2"/>
<ComboBoxItem Content="Address Example 3"/>
</ComboBox>
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="41,214,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="35.824" Width="154" FontSize="21.333" FontFamily="Adobe Arabic" Text="{Binding ElementName=cb_Address,Path=SelectedItem.Content,Mode=OneWay}"/>
This should definitely work, if it does then I would assume both issues you are having are due to the ItemTemplate you are using. Make sure orderheaderTemplate is binding your display data (address) from orderheader to the orderheaderTemplate Content property.
Edit 2 redo
This example should allow you to achieve the desired result - I have now built a project in order to test this. I have also built the XmlDataProvider in so you can see how its working.
<Window.Resources>
<!-- simple data example -->
<XmlDataProvider x:Key="orderheaderDataSource" XPath="/Info">
<x:XData>
<Info xmlns="">
<!-- these are basically the rows of your actual data source -->
<Order ID="001" Address="Example 1" City="New York" fname="John" lname="Smith" />
<Order ID="002" Address="Example 2" City="London" fname="Jane" lname="Doe" />
<Order ID="003" Address="Example 3" City="Paris" fname="Joe" lname="Bloggs" />
</Info>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<StackPanel>
<!-- combo to be replaced with your working example -->
<ComboBox x:Name="cb_Address" DataContext="{StaticResource orderheaderDataSource}" ItemsSource="{Binding XPath=Order}" DisplayMemberPath="#Address" HorizontalAlignment="Left" VerticalAlignment="Top" Width="90" IsEditable="True"/>
<!-- textblock shows what is being displayed in the combo -->
<TextBlock x:Name="tb_Address" Text="{Binding ElementName=cb_Address,Path=Text}"/>
</StackPanel>
You will need to swap out the binding information to match your data source. But this should let you play around to see what the properties are doing.
I believe you got the combo to display properly using the below (this just skips a couple of the properties from the example):
ItemsSource="{Binding XPath=/dataroot/orderheader/address}
This makes the DataContext and DisplayMemberPath redundant as you are pointing straight to the address.
Using the above code
<Window x:Class="CC_Ticketing_WPF.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:CC_Ticketing_WPF"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="600">
<StackPanel>
<!-- I think this what you said populated properly in the comments -->
<ComboBox x:Name="cb_Address" ItemsSource="{Binding XPath=/dataroot/orderheader/address}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="90" IsEditable="True"/>
<!-- this should replicate what you see in the combobox -->
<TextBlock x:Name="tb_Address" Text="{Binding ElementName=cb_Address,Path=Text}"/>
</StackPanel>
</Window>
This should work based on the feedback you have given it's very basic, and will limit how you can present that data if you want to use a template or any multi-bindings. Hopefully it will work for you as is.
What you have done on your own was skip the DisplayMemberPath from my last post by using "/address" in the ItemsSource property in your ComboBox.
Then the text is being bound in the TextBlock to the Text Property of your ComboBox.
Alternatively You can solve as in your origional post:
XAML: (in your combobox)
SelectionChanged="cb_Address_SelectionChanged"
C#:
private void cb_Address_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
tb_Address.Text = ((ComboBoxItem)cb_Address.SelectedItem).Content.ToString;
}
Assuming The pure XAML approach continues to fail.

not able to disable a particular text block in custom control

I have a custom control which contains one text-block, one combo-box and one hyper-link button.
<UserControl x:Class="IXExpress.Controls.WorkspaceIndexes"
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:telerikSdk="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
Height="Auto" Width="Auto">
<Grid x:Name="LayoutRoot">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<TextBlock x:Name="IndexNameTextBlock" Text="{Binding ApplicationStrings.SelectIndexName, Source={StaticResource ResourceWrapper}, Mode=OneTime}" Margin="3,5" TextAlignment="Left" VerticalAlignment="Center" Visibility="Visible"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<telerikSdk:RadComboBox x:Name="IndexNameCB"
DisplayMemberPath="IndexName"
HorizontalAlignment="Center"
IsDropDownOpen="False"
Margin="3,0,3,5"
MinWidth="150"
Width="150"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Visibility="Visible"
SelectionChanged="IndexNameCB_SelectionChanged"/>
<HyperlinkButton x:Name="CreateNewIndexLink"
Content="Create New"
VerticalContentAlignment="Center"
Click="CreateNewIndexLink_Click"/>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
I am using it on another page as following:
<StackPanel Orientation="Vertical">
<customControls:WorkspaceIndexes x:Name="WorkspaceIndexes" IsMoreTextRequired="True" Margin="3"/>
</StackPanel>
The issue is, on some condition when I want to disable this control but it only disables combo-box and hyper-link button.
code:
if (my condition)
WorkspaceIndexes.IsEnabled = true;
else
WorkspaceIndexes.IsEnabled = false;
Result:
http://imgur.com/L6tbOwo
I also don't see IsEnabled option for "IndexNameTextBlock" text-block, Why is that?
You can't see the IsEnabled property for the TextBlock because it doesn't have the property. The other Elements are derived from Control, they can be enabled and disabled. The TextBlock is no Control. Disabling a TextBlock would be meaningless. It just displays text. No user interaction possible.
If you need it to be grayed out you have to change either its Foreground color, or reduce its Opacity, or place a semi-transparent Rectangle/Border over it.

MVVM - Access command from different class in XAML

In my project I have a TitleView and GameView. When the program launches, TitleView is displayed. The user clicks a button and GameView is displayed. I am using MVVM Light which includes MainViewModel which has commands to switch to the desired views:
From MainViewModel.cs
GameViewCommand = new RelayCommand(() => ExecuteGameViewCommand());
private void ExecuteGameViewCommand()
{
CurrentViewModel = MainViewModel._gameViewModel;
}
In TitleView.xaml, I need to access this command and I don't know how. I am very much a novice when it comes to XAML.
From TitleView.xaml
<UserControl x:Class="AoW.Views.TitleView"
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:vm="clr-namespace:AoW.ViewModels"
mc:Ignorable="d"
d:DesignWidth="1020"
d:DesignHeight="740"
Width="1020"
Height="740">
<Button Content="New Game"
//This needs to bind to GameViewCommand in MainViewModel.cs
Command="{Binding GameViewCommand}"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
If I put the following line into TitleView.xaml...
DataContext="{Binding Main, Source={StaticResource Locator}}"
... I can access GameViewCommand, but I can't access any local commands.
What can I do to gain access to GameViewCommand while maintaining control of local commands?
If providing additional code would be helpful, please let me know.
I've fixed the problem. All I had to was this:
<Button Content="New Game"
Command="{Binding GameViewCommand}"
DataContext="{Binding Main, Source={StaticResource Locator}}"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Button Content="Say Hello"
Command="{Binding SayHelloCommand}"
Grid.Column="2"
Grid.Row="2"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
Turns out it was a very easy fix.

How to send data from one User Control to another User Control?

Say I have these two User Controls. How would I pass data entered in the TextBox from ControlOneto the TextBox in ControlTwo when the Button in ControlOne is clicked?
<UserControl x:Class="Project.ControlOne"
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="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="MyTextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100" />
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Send" Click="Button_Click" />
</StackPanel>
</Grid>
</UserControl>
...
namespace Project
{
public partial class ControlOne : UserControl
{
public ControlOne()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}
}
<UserControl x:Class="Project.ControlTwo"
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="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="MyTextBox" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100" />
</StackPanel>
</Grid>
</UserControl>
Your two user controls should have no knowledge of each other (unless one contains the other). That's why you can't "pass data" between them. The idea behind a user control is that you can drop it anywhere as many times as needed. If ControlOne knew about ControlTwo, what would happen if you used them separately? Or had three ControlTwos in the same place?
The layer which contains both of them should be the one to read a value from one and set it to the other. If you want it to happen on the button press, you should look into event handling so the parent can know when the control's button is pressed.

Does WPF have a "static box" control?

Please see this image for what I'm referring to as a static box:
I'm not sure if that is it's proper name.
The box should be able to hold an arbitrary child control (panel etc.) inside.
In WPF, it is called a GroupBox
See the MSDN documentation for the control:
http://msdn.microsoft.com/en-us/library/system.windows.controls.groupbox.aspx
How to use it
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<GroupBox Header="Test 1">
<StackPanel Margin="6">
<RadioButton x:Name="option1RadioButton" Content="Option 1" />
<RadioButton x:Name="option2RadioButton" Content="Option 2" />
<RadioButton x:Name="option3RadioButton" Content="Option 3" />
</StackPanel>
</GroupBox>
</Window>
Cool features
The WPF GroupBox is a bit more powerful than your standard Win32 group box. Instead of just being able to set text in the header, you can set any sort of content you want, such as images, or other controls:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<GroupBox>
<GroupBox.Header>
<StackPanel Orientation="Horizontal">
<Button Content="Test 1" />
<Label Content="Test 2" />
<Button Content="Test 3" />
</StackPanel>
</GroupBox.Header>
<StackPanel Margin="6">
<RadioButton x:Name="option1RadioButton" Content="Option 1" />
<RadioButton x:Name="option2RadioButton" Content="Option 2" />
<RadioButton x:Name="option3RadioButton" Content="Option 3" />
</StackPanel>
</GroupBox>
</Window>
Yep, that's called a GroupBox in WinForms/WPF world.
To set the text in it, set the Header property:
<GroupBox Header="Some Text">
<Grid>
<!--Other Controls-->
</Grid>
</GroupBox>

Categories