WPF PlacementTarget for PopUp at UserControl TextBox - c#

I would like to have a popup show at the bottom of each textbox in my window, as they are focused.
The user would be presented with the last few entries entered in that textbox. I would like the placement to be such that it would be at the bottom of the textbox currently focused.
This is my user control with the textbox:
<UserControl x:Class="PopupPlacement.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox Name="TextBox_MyControl" Text="enter your text here" Height="25" Width="200"/>
</StackPanel>
</UserControl>
Here is my window:
<Window x:Class="PopupPlacement.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PopupPlacement"
Title="MainWindow" Height="450" Width="800">
<Canvas>
<Grid ShowGridLines="False">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Domain" Margin="10"/>
<local:MyControl Grid.Column="1" x:Name="Domain" Margin="10"/>
<Label Grid.Row="1" Content="Username" Margin="10"/>
<local:MyControl Grid.Row="1" Grid.Column="1" x:Name="Username" Margin="10"/>
<Label Grid.Row="2" Content="Password" Margin="10"/>
<local:MyControl Grid.Row="2" Grid.Column="1" x:Name="Password" Margin="10"/>
<Button Grid.Row="3" Content="OK" Margin="10" Name="Button_OK"/>
<Button Grid.Row="3" Grid.Column="1" Content="Cancel" Margin="10"/>
<Popup PlacementTarget="{Binding ElementName=TextBox_MyControl}" Placement="Bottom"
IsOpen="{Binding ElementName=TextBox_MyControl, Path=IsKeyboardFocused}">
<ComboBox IsDropDownOpen="True">
<ComboBoxItem IsSelected="True">Item 1</ComboBoxItem>
<ComboBoxItem>Item 2</ComboBoxItem>
</ComboBox>
</Popup>
</Grid>
</Canvas>
</Window>
Appreciate any pointers.

For me, the best solution to a similar requirement was to write a Behavior that kind of mimics Intellisense.
I don't have any simple code at hand, but you could create and show a ListBox inside a Popup placed at the AssociatedObject's bottom. You can then bind the TextBox-related entries to the Behavior via a DependencyProperty.
Of course, there's a lot more to it like closing the Popup, re-using existing controls, handling key presses to access the ListBox, insert the selected value to the TextBox etc.
Here's a simple (untested) sketch.
public class IntellisenseBehavior : Behavior<TextBox>
{
public IEnumerable ItemsSource
{
get => (IEnumerable)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(IntellisenseBehavior), new UIPropertyMetadata(null));
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotKeyboardFocus += AssociatedObjectOnGotKeyboardFocus;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.GotKeyboardFocus -= AssociatedObjectOnGotKeyboardFocus;
//cleanup
}
private void AssociatedObjectOnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var popup = new Popup
{
ClipToBounds = false,
AllowsTransparency = true,
PopupAnimation = PopupAnimation.Fade,
HorizontalAlignment = HorizontalAlignment.Left
};
popup.SetValue(FocusManager.IsFocusScopeProperty, true);
popup.Placement = PlacementMode.Bottom;
popup.PlacementTarget = AssociatedObject;
var shadow = new SystemDropShadowChrome { Color = Colors.Transparent, MaxHeight = 200, Margin = new Thickness(0, 0, 5, 5) };
var listBox = new ListBox
{
ItemsSource = ItemsSource
}
((IAddChild)shadow).AddChild(listBox);
((IAddChild)popup).AddChild(shadow);
popup.IsOpen = true;
}
}
Attach it to all TextBoxes that you require to have this functionality and for instance use a converter to get the filtered entries you need.
<!-- Uses converter's public const string NameBox = "NameBox"; for filtering. -->
<TextBox>
<i:Interaction.Behaviors>
<IntellisenseBehavior ItemsSource="{Binding LastEntries, Converter={StaticResource FilterEntriesConverter}, ConverterParameter={x:Static FilterEntriesConverter.NameBox}}" />
</i:Interaction.Behaviors>
</TextBox>
Hope that helps.

Related

C# wpf caliburn.Micro MahApps HamburgerMenu.ContentTemplate data binding is not working

I'm making an application using Caliburn.Micro(for easy data binding and stuff) and MahApps.Metro(for designing).
I've created a View name 'MainView' which has HamburgerMenu of MahApps.
My issue is data binding is working fine under HamburgerMenu.ContentTemplate tag
Here is my HamburgerMenu.ContentTemplate xaml.
<Page x:Class="Sample.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:utils="clr-namespace:Omni.WindowsClient.Utils"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Omni.WindowsClient.Views"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="600">
<Page.Resources>
<DataTemplate x:Key="HamburgerMenuItem"
DataType="{x:Type mah:HamburgerMenuItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Margin="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="{Binding Glyph}"
Stretch="UniformToFill" />
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Foreground="White"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
</Page.Resources>
<Grid>
<mah:HamburgerMenu x:Name="HamburgerMenuControl"
SelectedIndex="0"
ItemTemplate="{StaticResource HamburgerMenuItem}"
OptionsItemTemplate="{StaticResource HamburgerMenuItem}"
IsPaneOpen="True"
DisplayMode="CompactInline"
cal:Message.Attach="[Event ItemClick] = [Action ShowDetails(HamburgerMenuControl.SelectedItem)]"
DataContext="{Binding RelativeSource={RelativeSource self}}">
<mah:HamburgerMenu.ItemsSource>
<mah:HamburgerMenuItemCollection>
<mah:HamburgerMenuItem Label="System Status">
<mah:HamburgerMenuItem.Tag>
<iconPacks:PackIconFontAwesome Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Tasks" />
</mah:HamburgerMenuItem.Tag>
</mah:HamburgerMenuItem>
<mah:HamburgerMenuItem Label="Inbox">
<mah:HamburgerMenuItem.Tag>
<iconPacks:PackIconFontAwesome Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Inbox" />
</mah:HamburgerMenuItem.Tag>
</mah:HamburgerMenuItem>
<mah:HamburgerMenuItem.Tag>
<iconPacks:PackIconFontAwesome Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Certificate" />
</mah:HamburgerMenuItem.Tag>
</mah:HamburgerMenuItem>
</mah:HamburgerMenuItemCollection>
</mah:HamburgerMenu.ItemsSource>
<mah:HamburgerMenu.ContentTemplate>
<DataTemplate DataType="{x:Type mah:HamburgerMenuItem}">
<Grid utils:GridUtils.RowDefinitions="48,*">
<!--cal:Action.TargetWithoutContext="{Binding ElementName=HamburgerMenuControl, Path=DataContext}"-->
<Border Grid.Row="0"
Background="{DynamicResource MahApps.Metro.HamburgerMenu.PaneBackgroundBrush}">
<TextBlock x:Name="Header"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="24"
Foreground="White" />
<!--Text="{Binding Path=Header, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"-->
</Border>
<Frame Grid.Row="1"
cal:Message.Attach="RegisterFrame($source)"
DataContext="{x:Null}"
NavigationUIVisibility="Hidden" />
</Grid>
</DataTemplate>
</mah:HamburgerMenu.ContentTemplate>
</mah:HamburgerMenu>
</Grid>
</Page>
and respective view model code is:
using Caliburn.Micro;
using MahApps.Metro.Controls;
using System.Windows.Controls;
namespace Sample.ViewModels
{
public class MainViewModel : Screen
{
private readonly SimpleContainer _container;
private INavigationService _navigationService;
private string _header;
public string HeaderTitle
{
get { return _header; }
set
{
_header = value;
NotifyOfPropertyChange();
}
}
public MainViewModel(SimpleContainer container)
{
this._container = container;
DisplayName = "Main";
}
public void RegisterFrame(Frame frame)
{
_navigationService = new FrameAdapter(frame);
_container.Instance(_navigationService);
_navigationService.NavigateToViewModel(typeof(SystemStatusViewModel));
HeaderTitle = "System Status";
}
public void ShowDetails(HamburgerMenuItem menuItem)
{
switch (menuItem.Label)
{
case "System Status":
_navigationService.NavigateToViewModel(typeof(SystemStatusViewModel));
HeaderTitle = "System Status";
break;
case "Inbox":
_navigationService.NavigateToViewModel(typeof(InboxViewModel));
HeaderTitle = "Inbox";
break;
default:
break;
}
}
}
}
I want to change View in frame under HamburgerMenu.ContentTemplate when I click on menu item.
Like System Status view is SystemStatusView
and Inbox view is InboxView.
My code is working fine (it changes the view in frame and change the Header label too) if I don't use HamburgerMenu.ContentTemplate. But I want to use HamburgerMenu.ContentTemplate to work with HamburgerMenu.
Thanks!
If it's working fine if you don't use HamburgerMenu.ContentTemplate, but stops working when you do, the problem is probably with you overwriting the default template in a way that doesn't support all functionalities of a control.
I'd suggest you to use Blend to get the default HamburgerMenu.ContentTemplate, then just edit it to your needs, without changing too much (keep in mind that names of controls used as a template may have a crucial meaning, so be careful what you are editing).
If you don't know how to use Blend to get your control's template, here is a simple tutorial described in a documentation of Telerik controls (don't worry, it works the same for all controls). You just need to create copy of a HamburgerMenu.ContentTemplate, paste it to your application and you are good to go (editing).

MVVM access Richtextbox flowdocument from VM

I am trying to make a RichTextBox with a FlowDocument that I can insert text at the caret position. I can add text to the end of the document. I think I am missing something in my setup to that allows my VM to access the Flowocument or I am setting it up wrong. If I create a FlowDocument in my VM and try to set my RichTextBox to it I get an error that my MyEditor (RichTextBox) does not exist. I can add text to the RichTextBox using what I call the AddItemBtn from a ListBox so at least that much works.
My question is "How should I set my RichTextBox/FlowDocument up?
XAML code
<Window x:Class="Scripter.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Scripter.ViewModels"
xmlns:wpftoolkit="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
Title="MainWindow" Height="350" Width="725">
<Grid HorizontalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" Height="72" Margin="10,14,0,0" VerticalAlignment="Top" Width="auto">
<WrapPanel HorizontalAlignment="Left" Height="50" Margin="10,0,0,0" VerticalAlignment="Top">
</WrapPanel>
<Button x:Name="OpenFilesBtn" Content="Open" HorizontalAlignment="Left" Margin="15,10,0,0" VerticalAlignment="Top" Width="75" Command="{Binding OpenFileBtn}"/>
<Button x:Name="SavefilesBtn" Content="Save" HorizontalAlignment="Left" Margin="104,10,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveFileBtn}"/>
<TextBlock x:Name="OpenFile" Text="{Binding OpenFile,Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="15,37,0,0" VerticalAlignment="Top" Width="353"/>
<ComboBox x:Name="TipsBtn" SelectedIndex="0" ItemsSource="{Binding Path=Tabs, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectedOption}" HorizontalAlignment="Left" Margin="538,10,0,0" VerticalAlignment="Top" Width="120"/>
<Button x:Name="AddItemBtn" Content="Add Item" HorizontalAlignment="Left" Margin="417,10,0,0" VerticalAlignment="Top" Width="100" Command="{Binding AddItemBtn}" CommandParameter="{Binding ElementName=AddItemList,Path=SelectedItem}"/>
</Grid>
<Grid Margin="10,100,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<RichTextBox Grid.Column="0" x:Name="MyEditor" SelectionChanged="MyEditor_SelectionChanged" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="0" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" IsDocumentEnabled="True" AcceptsTab="True" AcceptsReturn="True" >
<RichTextBox.Resources>
<Style TargetType="{x:Type Paragraph}">
<Setter Property="Margin" Value="0" ></Setter>
<Setter Property="FontSize" Value="15"></Setter>
</Style>
</RichTextBox.Resources>
<FlowDocument >
<Paragraph >
<Run Text="{Binding TestText}" ></Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
<ListBox x:Name="AddItemList" Grid.Column="1" Width="Auto" Height="Auto" ItemsSource="{Binding Path=OptionsToChoose}" SelectedItem="ItemSelected">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="TextSelected" Text="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
VM code that has the issue
public ScripterViewModel()
{
ScripterModel scripterModel = new ScripterModel();
ObservableCollection<string> tabsChoice = new ObservableCollection<string>();
tabsChoice.Add("Tabs");
tabsChoice.Add("Buttons");
Tabs = tabsChoice;
this.OpenFileBtn = new DelegateCommand(chooseFile, canChooseFile).ObservesProperty(() => OpenFile);
this.SaveFileBtn = new DelegateCommand(saveFile, canSaveFile).ObservesProperty(() => SaveFile);
this.AddItemBtn = new DelegateCommand<Tabbed>(addItem);
FlowDocument flowDoc = new FlowDocument();
Paragraph p = new Paragraph(new Run("new paragraph"));
flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 1")));
flowDoc.Blocks.Add(p);
//MyEditor = flowDoc;
}
public void MyEditor_SelectionChanged(object sender, RoutedEventArgs e)
{
// TextRange tempRange = new TextRange(MyEditor.Document.ContentStart, MyEditor.Selection.Start);
MessageBox.Show("Selection Changed");
}
private string _testText;
public string TestText
{
get
{
return _testText;
}
set
{
string _temp;
_temp = _testText + value;
SetProperty(ref _testText, value);
}
}
Hey I am new to WPF and MVVM but I'll give my best to help you. So don't blame me if I'm wrong.
1. Set Window.DataContext
First of all you have to tell your View where it can get the data from.
This can be done by adding this code to your View.xaml:
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
But make sure your namespace variable (here "local") points to your ViewModels.
xmlns:local="clr-namespace:Client.ViewModel"
This for ex. points to my ViewModel folder.
2. Define a OnPropertyChanged method
Your View won't know if you have modified a variable. So you need a method to notify your View about the changes.
First of all implement the interface INotifyPropertyChanged to your ViewModel.
public class MainViewModel : ViewModelBase, INotifyPropertyChanged
Now add this code:
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
3. Use OnPropertyChanged
So now you have a method to tell your View that a variable has changed but how do you use it?
To explain this to you I'll use your FlowDocument flowDoc.
So let's begin by defining your FlowDocument setting up :
private FlowDocument _flowDoc;
Now lets write a getter & setter for flowDoc:
public FlowDocument FlowDoc
{
get
{
return _flowDoc;
}
set
{
_flowDoc = value;
}
}
Now it's time to use our OnPropertyChanged method which we created in 2.
In the setter section you want to add the following Code:
OnPropertyChanged("variable");
Your result should now look like this:
public FlowDocument FlowDoc
{
get
{
return _flowDoc;
}
set
{
_flowDoc = value;
OnPropertyChanged("FlowDoc");
}
}
Important: remember to apply this to all your variables!
4. Use MVVM pattern right
In MVVM you have a Model a View and a ViewModel.
The Model is for your data so if possible don't store data in your ViewModel instead use a data class for ex.
You may have a look at this and/or this.
As I said in the beginning I'm new to all of this but i hope it helps
you. Feel free to ask.

Set button margin with auto window size

I've created a simple custom messagebox that automatically scales depending on the length of the text to be displayed :
public partial class CustomMessageBox : Window
{
public CustomMessageBox(string title, string text)
{
InitializeComponent();
ResizeMode = ResizeMode.NoResize;
label.Content = text;
Title = title;
}
public static void Show(string title, string text)
{
CustomMessageBox box = new CustomMessageBox(title, text);
box.SizeToContent = SizeToContent.WidthAndHeight;
box.ShowDialog();
}
private void button_Click(object sender, RoutedEventArgs e)
{
Close();
}
}
This works nicely however my button is clamping to the bottom side of the window because the window automatically scales :
And the button seems to be moving once the message gets longer :
How would I make sure the button stays centered and have a margin of around 10px from the bottom so it doesn't look that clamped?
I tried to set the Margin manually but that doesn't seem to work.
XAML (largely generated by the designer) :
<Window x:Class="RapidEvent.CustomMessageBox"
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:RapidEvent"
mc:Ignorable="d"
Background="{DynamicResource WindowBackgroundBrush}"
Title="" Height="Auto" Width="Auto">
<Grid>
<StackPanel>
<Label x:Name="label" Content="" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" FontSize="13px" RenderTransformOrigin="0.392,0.486"/>
<Button x:Name="button" x:FieldModifier="public" IsDefault="True" Content="_Ok" HorizontalAlignment="Left" Margin="110,40,0,0" VerticalAlignment="Top" Width="80" Height="21" Click="button_Click"/>
</StackPanel>
</Grid>
</Window>
Simply change your StackPanel to a Grid and the HorizonalAlignment of your button to Center and take off all but the bottom margin. You'll also need to set the VerticalAlignment to Bottom. You also need to put the button on row 1.
This way the button will be clamped to the bottom of the dialog and always centred.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label x:Name="label" Content=""
HorizontalAlignment="Left" Margin="10,0,0,0"
VerticalAlignment="Top" FontSize="13px"
RenderTransformOrigin="0.392,0.486"/>
<Button Grid.Row="1" x:Name="button" x:FieldModifier="public"
IsDefault="True" Content="_Ok"
HorizontalAlignment="Center" Margin="0,0,0,20"
VerticalAlignment="Bottom" Width="80" Height="21"/>
</Grid>
Use grid instead of StackPanel:
<Grid >
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<telerik:Label x:Name="label" Content="LSFFD" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" FontSize="13px" RenderTransformOrigin="0.392,0.486"/>
<Button Grid.Row="1" x:Name="button" x:FieldModifier="public" Content="_Ok" HorizontalAlignment="Center" Margin="0 0 0 10" VerticalAlignment="Bottom" Width="80" Height="21" Click="button_Click"/>
</Grid>

Unable to see my controls in MainPage.g.cs of my MainPage.xaml

I have a simple question about XAML.
I created a grid element inside another grid and added a textblock and a web browser in it. However, I am unable to access it in MainPage.xaml.cs using their name (e.g. this.LastName) doesn't work. On further debugging, I saw that they are not declared in MainPage.g.cs. Since MainPage.g.cs is auto defined, I don't know how to fix it. Can someone help please? Below is my C# and XAML code. Thanks!
========================================================
public partial class MainPage : Microsoft.Phone.Controls.PhoneApplicationPage {
internal System.Windows.Controls.Grid LayoutRoot;
internal System.Windows.Controls.Grid ContentPanel;
internal Microsoft.Phone.Controls.LongListSelector MainLongListSelector;
internal System.Windows.Controls.Image RefreshIcon;
private bool _contentLoaded;
/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Windows.Application.LoadComponent(this, new System.Uri("/Suod;component/MainPage.xaml", System.UriKind.Relative));
this.LayoutRoot = ((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
this.ContentPanel = ((System.Windows.Controls.Grid)(this.FindName("ContentPanel")));
this.MainLongListSelector = ((Microsoft.Phone.Controls.LongListSelector)(this.FindName("MainLongListSelector")));
this.RefreshIcon = ((System.Windows.Controls.Image)(this.FindName("RefreshIcon")));
}
}
========================================================
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="MainLongListSelector" Margin="-12,-97,0,97" ItemsSource="{Binding Items}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="12,100,0,45">
<Grid x:Name="CompanyContentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Name="LastName" Text="{Binding Name}" TextWrapping="Wrap" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
<phone:WebBrowser Grid.Row="5" Height="400" Name="WebBrowser" Margin="12,-6,24,0" FontFamily="Portable User Interface"/>
</Grid>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
<Grid Grid.Row="2" >
<Image Source="/Assets/Refresh.png" Name="RefreshIcon" Width="80" Height="80" Tap="Image_Tap"/>
</Grid>
I think the problem is that your textblock i too deep in xaml code. I think Data Binding should be enough in this situation but there is a way to go around this problem. You have to subscribe this element to some event(like Loaded) and save sender to some property in code behind:
<TextBlock Loaded="LastName_Loaded" Grid.Row="0" Name="LastName" Text="{Binding Name}" TextWrapping="Wrap" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
public TextBlock lastName;
private void LastName_Loaded(object sender, RoutedEventArgs e)
{
lastName= (TextBlock)sender;
}
Now you are able to access this element in code behind.

Hide/Display XAML elements or block LostFocus event

I have a page containing two StackPanels, each containing one TextBox and one Button:
<StackPanel x:Name="Row1">
<TextBox x:Name="TextBox1" Text="" GotFocus="OnFocusHandler" LostFocus="OffFocusHandler"/>
<Button x:Name="Button1" Content="Convert" Click="OnClickHandler" Visibility="Collapsed"/>
</StackPanel>
<StackPanel x:Name="Row2">
<TextBox x:Name="TextBox2" Text="" GotFocus="OnFocusHandler" LostFocus="OffFocusHandler"/>
<Button x:Name="Button2" Content="Convert" Click="OnClickHandler" Visibility="Collapsed"/>
</StackPanel>
I would like to do the following:
When a textbox has focus, the other textbox must be hidden and the corresponding button must show
When a textbox is out of focus, we are back to the original display: only empty textboxes are visible
I don't want the button to be able to trigger the OffFocusHandler
This is the current code that I have for the three handlers:
private void OnFocusHandler(object sender, RoutedEventArgs e)
{
TextBox SenderTextBox = (TextBox)sender;
if (SenderPanel.Name == "TextBox1")
{
Button1.Visibility = Visibility.Visible;
}
else if (SenderPanel.Name == "TextBox2")
{
Button2.Visibility = Visibility.Visible;
}
}
private void OffFocusHandler(object sender, RoutedEventArgs e)
{
TextBox1.Text = "";
TextBox2.Text = "";
Button1.Visibility = Visibility.Collapsed;
Button2.Visibility = Visibility.Collapsed;
}
private void OnClickHandler(object sender, RoutedEventArgs e)
{
// some stuff unrelated to my issue
}
How do I avoid the button clicking to trigger the OffFocusHandler code?
Is there another way to code this? I'm a complete beginner so I may not think the right way.
You can just Bind to the TextBox.IsFocused property in Xaml, and use the BooleanToVisibilityConverter to show/hide the button.
Example:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="MainWindow" Height="300" Width="400" Name="UI" >
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolTovisible" />
</Window.Resources>
<Grid>
<StackPanel x:Name="Row1" Height="54" VerticalAlignment="Top">
<TextBox x:Name="TextBox1" Text="" />
<Button x:Name="Button1" Content="Convert" Visibility="{Binding ElementName=TextBox1, Path=IsFocused, Converter={StaticResource BoolTovisible}}"/>
</StackPanel>
<StackPanel x:Name="Row2" Margin="0,60,0,0" Height="51" VerticalAlignment="Top">
<TextBox x:Name="TextBox2" Text="" />
<Button x:Name="Button2" Content="Convert" Visibility="{Binding ElementName=TextBox2, Path=IsFocused, Converter={StaticResource BoolTovisible}}"/>
</StackPanel>
</Grid>
</Window>
for each element, there is a Visibility tag, it is "Visible" by default but you can assign "Hidden" or "Collapsed" as follow:
<RadioButton Margin="20,118,318,-43" GroupName="MCSites" Visibility="Hidden">
Radio Button Description
</RadioButton>

Categories