I have a TextBlock with its HorizontalAlignment property set to Stretch, and would like it to display different text based on different values of its width, e.g.:
VSTS if width < 70
VS Team Services if 70 <= width < 150
Visual Studio Team Services if 150 < width
This behavior can be achieved using the SizeChanged event of the TextBlock:
<TextBlock HorizontalAlignment="Stretch" TextTrimming="CharacterEllipsis" SizeChanged="VisualStudioTeamServicesTextBlock_SizeChanged"/>
private void VisualStudioTeamServicesTextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.NewSize.Width < 70)
(sender as TextBlock).Text = "VSTS";
else if (e.NewSize.Width < 150)
(sender as TextBlock).Text = "VS Team Services";
else
(sender as TextBlock).Text = "Visual Studio Team Services";
}
However I'm looking for a more elegant XAML-based solution, something that would look like:
<TextBlock HorizontalAlignment="Stretch" TextTrimming="CharacterEllipsis">
<TextBlock.Triggers>
<Trigger MaxWidth="70">
<Setter Property="Text" Value="VSTS"/>
</Trigger>
<Trigger MaxWidth="150">
<Setter Property="Text" Value="VS Team Services"/>
</Trigger>
<Trigger MinWidth="150">
<Setter Property="Text" Value="Visual Studio Team Services"/>
</Trigger>
</TextBlock.Triggers>
</TextBlock>
I guess it could be done in several different ways (using style triggers or visual state manager or maybe even some 3rd party library), but since I'm not an expert, I simply ask which would be the simplest for the given task. Working sample is much appreciated.
Adaptive triggers would be the best solution to your problem, since everything would be XAML-based, but unfortunately the visual states can only be applied based on the window properties.
By subclassing the StateTriggerBase class and you could expose Adaptive Triggers to a couple of aditional triggers situations such as Internet Connection, but accessing a Run-Time dependency object from there seems unfeasible, at least for me (I ain't no expert either).
Creating your own visual state and jumping between states depending on your Control's dimension would be another possible solution.
But all of these solutions share the same behind-logic, which is: somewhere there is code-behind which is tracking the dependency properties and puppeteering the outcome.
Might this be an XY Problem ?
I made a really lackluster solution where I created my own UserControl, and created a custom dependency property, which could share 3 states: Small, Medium, Big. But after that I realized that the solution which I had envisioned was not as useful as I had in mind.
In theory, there's a control which exposed a custom dependency property, which is set whenever the control size has changed (once again we cannot run from the Event logic). Only in the dependency property setter, I actually set the Text for our TextBox. The property setter is defined as private, so there's no way you can externally set this property value of this user control.
But you can read it, just like it's expected from a dependency property.
The purpose of this solution was honestly more about forcing me to explore the subject of creating custom controls, dependency properties or attached properties, rather than making something that would be of extreme value. But hopefully you might take some value from this,
UserControl:
Code-Behind
public sealed partial class TextBox : UserControl
{
public enum TextBoxOptions
{
Small = 0,
Medium = 1,
Big = 2
}
public static readonly DependencyProperty TrackingWidthProperty =
DependencyProperty.Register(
"Dependency",
typeof(TextBoxOptions),
typeof(TextBox),
new PropertyMetadata(false)
);
public TextBoxOptions TrackingWidth
{
get
{
return (TextBoxOptions)GetValue(TrackingWidthProperty);
}
private set
{
if (value == TextBoxOptions.Small) TextBoxRoot.Text = "VSTS";
else if (value == TextBoxOptions.Medium) TextBoxRoot.Text = "VS Team Services";
else TextBoxRoot.Text = "Visual Studio Team Services";
SetValue(TrackingWidthProperty, value);
}
}
public TextBlock()
{
this.InitializeComponent();
this.DataContext = this;
TextBoxRoot.SizeChanged += TextBoxRoot_SizeChanged;
}
private void TextBoxRoot_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (TextBoxRoot.ActualWidth < 600) TrackingWidth = TextBoxOptions.Small;
else if (TextBoxRoot.ActualWidth < 800) TrackingWidth= TextBoxOptions.Medium;
else TrackingWidth = TextBoxOptions.Big;
}
}
XAML:
<UserControl
x:Class="VisualStateTrigger.TextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VisualStateTrigger"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBox x:Name="TextBoxRoot"/>
</Grid>
</UserControl>
Outside of UserControl:
<Page
x:Class="VisualStateTrigger.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VisualStateTrigger"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="200"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<local:TextBlock Grid.Column="1" Grid.Row="1" x:Name="myTextBox" HorizontalAlignment="Stretch"/>
</Grid>
</Grid>
</Page>
Result
Conclusion:
I was having problems for low width dimensions, that you defined, that's why the numbers are bumped up.
Defining the Data Context like I did on the user control is a mistake from what I've gathered around, but this is working ...
Creating your own control lets you encapsulate all additional logic in the control itself. If you needed a bunch of this elements to share the same kind of behavior, you don't need to expose multiple event-handlers or create a common location for them to have access for those handlers, since it is actually part of their implementation.
And for a couple of more complex scenarios, I can imagine that exposing a couple of Dependency Properties might be extremely useful. Even for this situation, checking out TrackingWidth Dependency Property would tell you what's the current visual state of your control, and maybe that could be important for a couple of very specific situations.
Related
Getting acquainted with UWP. I'm developing an App for simulating electric circuits. There is a classic visual control called Frame, later called GroupBox in WPF.
It seems this control is absent in UWP.
There is a control called HeaderedContentControl in UWP.Toolkit library, but doesn't look the same. And seems the background and border properties don't work..
currently my code is:
<controls:HeaderedContentControl Margin="5"
BorderBrush="Black" BorderThickness="1"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<controls:HeaderedContentControl.Header>
<Border BorderBrush="Black" BorderThickness="1">
<Border.RenderTransform>
<TranslateTransform Y="-10"/>
</Border.RenderTransform>
<TextBlock Text="Resistor Value"/>
</Border>
</controls:HeaderedContentControl.Header>
<local:ComponentValueBox Unit="Ohm" HorizontalAlignment="Left"
Value="{x:Bind resistorValue, Mode=TwoWay}"
ValueChanged="changeR"/>
</controls:HeaderedContentControl>
And what I see (in the flyout) is:
Not quite like the GroupBox control..
What I would like to see is something like following:
What Should I do?
UWP is different from WPF. UWP is based on windows runtime, WPF is based on .NET Framework. They all use XAML to layout UI elments, but they have different XAML rendering engine. You could not think that MS dropped the old classic control. They're totally on the different platform. We call 'UWP' as Unversal Windows Platform. For now, you're not able to find such a 'GroupBox', but it's a new platform, you might be able to see such a control in the future. Anything is possible.
For your requirement, like #Muzib said, you entirely could make a custom control to meet your requirement. I used UserControl TextBlock Border ContentControl to make such a 'GroupBox' for your reference.
Please see my following code sample:
<UserControl
x:Class="AppGroupBox.GroupBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AppGroupBox"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<TextBlock x:Name="HeaderTitle" Text="Header" Margin="7 0 0 0" LayoutUpdated="HeaderTitle_LayoutUpdated"></TextBlock>
<Border BorderBrush="Black" x:Name="border" BorderThickness="0 2 0 0" Margin="100 10 3 3" CornerRadius="0 5 0 0"></Border>
<Border BorderBrush="Black" BorderThickness="2 0 2 2" Margin="3 10 3 3" CornerRadius="5">
<ContentControl x:Name="Content" Margin="10 10 10 10">
</ContentControl>
</Border>
</Grid>
public sealed partial class GroupBox : UserControl
{
public GroupBox()
{
this.InitializeComponent();
}
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(GroupBox), new PropertyMetadata("Your Header", HeaderPropertyChangedCallback));
public static void HeaderPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
(d as GroupBox).HeaderTitle.Text = e.NewValue?.ToString();
//(d as GroupBox).border.Margin = new Thickness((d as GroupBox).HeaderTitle.ActualWidth, 10, 3, 3);
}
}
public object CustomContent
{
get { return (object)GetValue(CustomContentProperty); }
set { SetValue(CustomContentProperty, value); }
}
// Using a DependencyProperty as the backing store for Content. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CustomContentProperty =
DependencyProperty.Register("CustomContent", typeof(object), typeof(GroupBox), new PropertyMetadata(null,PropertyChangedCallback));
public static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
(d as GroupBox).Content.Content = e.NewValue;
}
}
private void HeaderTitle_LayoutUpdated(object sender, object e)
{
border.Margin = new Thickness(HeaderTitle.ActualWidth+10,10,3,3);
}
}
<local:GroupBox Header="My GroupBox" Height="300" Width="500">
<local:GroupBox.CustomContent>
<StackPanel>
<RadioButton Content="r1"></RadioButton>
<TextBox></TextBox>
</StackPanel>
</local:GroupBox.CustomContent>
</local:GroupBox>
I don't think there's such controls in UWP. Most probably you have to make your own CustomControl to achieve something that looks exactly lik that in UWP.
But hey, you can achieve something like that with a 'customized' ListView. Look at this:
<ListView Header="I am a header" BorderThickness="1" BorderBrush="Red" Width="250" Height="200" SelectionMode="None">
<ListView.HeaderTemplate>
<DataTemplate>
<ListViewHeaderItem Content="{Binding}"/>
</DataTemplate>
</ListView.HeaderTemplate>
<RadioButton>Any Value</RadioButton>
<RadioButton>1% standard?</RadioButton>
<RadioButton>5% standard</RadioButton>
</ListView>
It produces this output:
Of course You can make these items more dense if you want so.
I have a LongListSelector which is inside a StackPanel. when this LLS is empty, it has infinite length and elements which are at the bottom of it can't be seen.
<StackPanel Orientation="Vertical">
<phone:LongListSelector>
</phone:LongListSelector>
</StackPanel>
but when I set it's ItemsSource, it gets fine. I tried assigning it's VerticalAlignment to top, but didn't solved the issue
How to make it's size not fill the form?
(I've edited this post to make it better)
First of all lets describe the problem you have, to do it we will use:
PROBLEM: infinite length of LongListSelector (LLS)- to be honest, it isn't a problem and it works like it should. Because LLS can have many many items and can be very long as its name says. The problem is that you use it in StackPanel without fixing its Height.
SOLUTIONS:
The first is very simple - just set the height of LLS. You will be sure that what should be below LLS, will be there. Like #Chris W mentioned - using LLS in StackPanel is not most forunate and can cause many problems - so avoid it.
<StackPanel Orientation="Vertical">
<phone:LongListSelector Height="300"/>
<TextBlock Text="Something/>
</StackPanel>
The most elegant and the best solution (also what #Chris W suggested) - to put your LLS into Grid. That way has many advantages and with Rowdefinitions your program will be independent of Phone resolution - all your controls will be there, were they should be.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="8*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<phone:LongListSelector Width="100" Grid.Row="0"/>
<TextBlock Text="Something" Grid.Row="1"/>
</Grid>
The third solution is not as good ad previous, but shows other way to manage your Controls. You can override the way LLS is measured. But with this method you have to watch out for example: it will work ok with the problem, unless you add so many items that your Controls will be pushed off the screen. Also you will have to watch out for this.Width, which has to be defined. So many additional conditions you have to check, of course you can add more modifications and it will work, but as I said it's not as good as previous solutions.
namespace Extensions
{
public class LongListSelectorEx : LongListSelector
{
protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
{
if (this.ItemsSource == null)
return new System.Windows.Size(this.Width, 0);
if (this.ItemsSource.Count <= 0)
return new System.Windows.Size(this.Width, 0);
return base.MeasureOverride(availableSize);
}
}
}
In your xaml you have to add:
<phone:PhoneApplicationPage
// something before
xmlns:common="clr-namespace:Extensions"
// other things
>
<StackPanel Orientation="Vertical">
<common:LongListSelectorEx Width="200"/>
<TextBlock Text="Something/>
</StackPanel>
I want to change my content off an AppBar dynamicly whith this code:
<Page.Resources>
<local:AppBarSelector x:Key="myAppBarSelector"/>
</Page.Resources>
<Page.BottomAppBar>
<AppBar>
<ContentControl Content="{Binding SelectedItem, ElementName=listBox}" ContentTemplateSelector="{StaticResource myAppBarSelector}">
<ContentControl.Resources>
<DataTemplate x:Key="1">
<TextBlock Text="Hallo Welt 1" Foreground="White" />
</DataTemplate>
<DataTemplate x:Key="2">
<TextBlock Text="Hallo Welt 2" Foreground="White" />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</AppBar>
</Page.BottomAppBar>
And this is my Code behind:
public class AppBarSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
Debug.WriteLine((string)item);
if (item == null) return base.SelectTemplateCore(item, container);
var contentControl = (ContentControl)container;
var templateKey = (string)item;
return (DataTemplate)contentControl.Resources[templateKey];
}
}
But this method is nerver called.Even the Debug.WriteLine function. Where is my mistake?
Just after some comments here...
(note: this is a bit general but I can't be more specific w/o some more code to reflect the issues)
This should work 'as is' - I don't see any problems that would produce that (I check with similar example fast and it works well with .ItemsSource = new List<string>{...}.
So that's not the culprit - but it doesn't hurt what I suggested - make a proper MVVM binding to properties, make the list ObservableCollection<> - and also it's always recommended to have a more higher-level objects (instead of just string) as your items (helps in many cases with binding with similar issues - that object implements INotifyPropertyChanged etc. - and you bind to a 'property' there, not the entire object).
The other error suggests some issues as well.
And lastly to bind two contentControls together - you don't normally need events as such. You can use Triggers from the style or XAML directly - but most of the time just bind both to a property in the view-model - and handle the 'change' in your property 'setter'.
You should put up a small primer that repeats this - who knows it might help you realize what you're doing wrong.
I need to style several GridView throughout my application with the same visual styles. This style includes customizing the ItemsPanel property as well as the GroupStyle property.
My problem is that the GroupStyle property of GridView is not a dependency property. So the code I would have liked to write (see below) does not work.
Do you know a clean way to share a style (including GroupStyle) between several GridViews?
The only thing I can think of is using a GroupStyleSelector but it's kind of stupid since there is no selection to make: it's always the same GroupStyle that's being used. Moreover, I suspect it wouldn't be reflected at design time in VS & Blend.
The code I would love to use:
<GridView
ItemsSource="..."
ItemTemplate="..."
Style="{StaticResource MainMenuStyle}"/>
<Style TargetType="GridView" x:Key="MainMenuStyle">
<Setter Property="ItemsPanel">
<Setter.Value>
...
</Setter.Value>
</Setter>
<Setter Property="GroupStyle">
<Setter.Value>
<GroupStyle>
...
</GroupStyle>
</Setter.Value>
</Setter>
</Style>
I've got a magical happy solution.
You can create a custom Attached Property that you set in the Style, and upon setting it internally sets the GroupStyle property on the GridView.
Attached Property:
// Workaround for lack of generics in XAML
public class GroupStyleCollection : Collection<GroupStyle>
{
}
public class GroupStyleHelper
{
public static ICollection<GroupStyle> GetGroupStyle(ItemsControl obj)
{
return (ICollection<GroupStyle>)obj.GetValue(GroupStyleProperty);
}
public static void SetGroupStyle(ItemsControl obj, ICollection<GroupStyle> value)
{
obj.SetValue(GroupStyleProperty, value);
}
public static readonly DependencyProperty GroupStyleProperty =
DependencyProperty.RegisterAttached(
"GroupStyle",
typeof(ICollection<GroupStyle>),
typeof(GroupStyleHelper),
new PropertyMetadata(null, OnGroupStyleChanged));
private static void OnGroupStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ItemsControl itemsControl = d as ItemsControl;
if (itemsControl == null)
return;
RefreshGroupStyle(itemsControl, GetGroupStyle(itemsControl));
}
private static void RefreshGroupStyle(ItemsControl itemsControl, IEnumerable<GroupStyle> groupStyle)
{
itemsControl.GroupStyle.Clear();
if (groupStyle == null)
return;
foreach (var item in groupStyle)
{
itemsControl.GroupStyle.Add(item);
}
}
}
XAML Style:
<Style TargetType="ItemsControl">
<Setter Property="GroupStyleTest:GroupStyleHelper.GroupStyle">
<Setter.Value>
<GroupStyleTest:GroupStyleCollection>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" FontSize="15" Text="{Binding Path=Name}" Foreground="HotPink"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GroupStyleTest:GroupStyleCollection>
</Setter.Value>
</Setter>
</Style>
Disclaimer: I'm testing this in WPF rather than WinRT but it should work the same, as far as I can tell. That's also why I'm using an ItemsControl rather than GridView, but the property is ItemsControl.GroupStyle anyway.
I've a solution and that will definitely work as per your question, but though you should decide whether to use that in your case or not.
If you have to make same style of a control in all over the project, then you should make one common folder and in that folder
create one "Custom User Control" and apply all of your style and
customize it however you want.
After that when you need to apply that same kind of style on same control (any grid control) then simply add that customized user
control instead of predefined control
By doing this you'll also achieve MVC architecture and modularity.
I'm developing Windows 8 Metro app in C# with XAML, and in that whenever i wanted this approach then i always use this solution and it always works...
to create custom user control, you should use visual studio & in that right click on project -> add -> new item -> User Control
(Sorry if you couldn't find your solution here, but i think this might help...)
I want to implement auto-complete on a textbox in a Windows 8 UI / Metro UI app using C#/XAML.
At the moment, when the soft / touch keyboard shows, it obscures the auto-complete box. However, on the text box focus, Windows 8 automatically scrolls the entire view up and ensures the text box is in focus.
In reality, all I want is the view to scroll up a little more (in fact, by the height of the auto-complete box).
I realise I can intercept the Showing event of InputPane.GetForCurrentView()
I can set InputPaneVisibilityEventArgs.EnsuredFocusedElementInView to true inside the Showing event fine (so Windows won't try to do anything).... however, how can I invoke the same scrolling functionality that Windows 8 would do, but ask it to scroll a little more!?
Here's the code for the main page:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,200,0,0">
<TextBlock HorizontalAlignment="Center" FontSize="60">App 1</TextBlock>
<TextBlock HorizontalAlignment="Center">Enter text below</TextBlock>
<TextBox HorizontalAlignment="Center" Margin="-10,0,10,0" Width="400" Height="30"/>
<ListBox HorizontalAlignment="Center" Width="400">
<ListBoxItem>Auto complete item 1</ListBoxItem>
<ListBoxItem>Auto complete item 2</ListBoxItem>
<ListBoxItem>Auto complete item 3</ListBoxItem>
<ListBoxItem>Auto complete item 4</ListBoxItem>
<ListBoxItem>Auto complete item 5</ListBoxItem>
</ListBox>
</StackPanel>
</Grid>
If you start up the simulator with the lowest resolution, use the hand to "touch" the textbox, this will bring up the soft keyboard. In the real app, the auto complete list will appear with items as the user enters text.
So in a nutshell, how can I move the screen up a bit more so the user can see the entire autocomplete list?
Bear in mind, in the real app, it'll be worse, as the user may not even notice the autocomplete list appearing "underneath" the keyboard.
I really would appreciate some advice, many thanks!
I have created an AutoCompleteBox for Windows Store apps, the nuget package is available at https://nuget.org/packages/AutoCompleteBoxWinRT
Ok, here is how I would tackle this since I cannot seem to find any way to control the scrolling of the app based on the appearance of the keyboard. I would create a user control that would form the basis for the auto-complete textbox.
<UserControl
x:Class="App6.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App6"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<TextBox x:Name="textBox" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" GotFocus="textBox_GotFocus" LostFocus="textBox_LostFocus" />
<ListBox x:Name="listBox" Height="150" Margin="0,-150,0,0" VerticalAlignment="Top" Visibility="Collapsed"/>
</Grid>
This is an incredibly basic implementation, so you will have to tweak to meet your needs.
Then, I would add the following code-behind to the user control
public sealed partial class MyUserControl1 : UserControl
{
// Rect occludedRect;
bool hasFocus = false;
public MyUserControl1()
{
this.InitializeComponent();
InputPane.GetForCurrentView().Showing += MyUserControl1_Showing;
}
void MyUserControl1_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
if (hasFocus)
{
var occludedRect = args.OccludedRect;
var element = textBox.TransformToVisual(null);
var point = element.TransformPoint(new Point(0, 0));
if (occludedRect.Top < point.Y + textBox.ActualHeight + listBox.ActualHeight)
{
listBox.Margin = new Thickness(0, -listBox.ActualHeight, 0, 0); // Draw above
}
else
{
listBox.Margin = new Thickness(0, textBox.ActualHeight, 0, 0); // draw below
}
}
}
private void textBox_GotFocus(object sender, RoutedEventArgs e)
{
listBox.Visibility = Windows.UI.Xaml.Visibility.Visible;
hasFocus = true;
}
private void textBox_LostFocus(object sender, RoutedEventArgs e)
{
listBox.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
hasFocus = false;
}
}
Next steps would be to expose properties to pass data to be bound to the ListBox. Hard core would be ListBoxItem templating and more, depending on how reusable you wanted it to be.