StringUpDown in WPF? - wpf

I have a question regarding the following question about NumericUpDown:
Good NumericUpDown equivalent in WPF?
How I can do this for 12 months of a year? I am planning to use a vertical ScrollBar with a textbox. I want to link the vertical ScrollBar up and down clicks to increment and decrement the months in the textbox using C#.
<ScrollBar x:Name="scbm"
HorizontalAlignment="Left" Height="26" Margin="230,195,0,0"
VerticalAlignment="Top" RenderTransformOrigin="0.542,0.83"/>
<TextBox x:Name="txtm"
HorizontalAlignment="Left" Height="23" Margin="139,195,0,0"
TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="66"/>
Can anyone tell me how I can accomplish this?

You can have a look This article that does something similar with a datepicker.
Basically you'll want to have a property for the month, and depending on your approach (code behind / mvvm), handle the click events on the up/down buttons, or the keyboard keydown event to handle them logic (so in your case, add the up/down buttons, and wire them to the events, naming them appropriately).
For example, having this on your xaml:
<DatePicker ... PreviewKeyDown="PreviewKeyDown_EventHandler" ... />
And something like this in your code behind:
private void PreviewKeyDown_EventHandler(object sender, System.Windows.Input.KeyEventArgs e)
{
// Avoid them nasty exceptions is the user hits "up" or "down" with no date selected:
if (sender == null || ((DatePicker)sender).SelectedDate == null)
return;
// Do this on up
if (e.Key == Key.Up)
{
((DatePicker)sender).SelectedDate =
((DatePicker)sender).SelectedDate.GetValueOrDefault().AddMonths(1);
}
// And this on down
if (e.Key == Key.Down)
{
((DatePicker)sender).SelectedDate =
((DatePicker)sender).SelectedDate.GetValueOrDefault().AddMonths(-1);
}
}
That example uses a datetime as the property, but you can do similar things with an int if that's what you're after.
(again, have a look at the link for more options, examples, and code example if you'd like)
Edit:
This doesn't have theh benefits of the up/down keys like the article's example, but this works:
<ScrollBar x:Name="scbm"
SmallChange="1" Maximum="12" Minimum="1"
Value="{Binding MonthScrollBar}"
HorizontalAlignment="Left" Height="26" Margin="230,195,0,0"
VerticalAlignment="Top" RenderTransformOrigin="0.542,0.83" />
<TextBox x:Name="txtm"
Text="{Binding MonthScrollBar}"
HorizontalAlignment="Left" Height="23" Margin="139,195,0,0"
TextWrapping="Wrap" VerticalAlignment="Top" Width="66" />
On my ViewModel (or your codebehind, if you want, do something similar)
public int MonthScrollBar
{
get { return _monthScrollBar; }
set { _monthScrollBar = value;
RaisePropertyChanged("MonthScrollBar");}
}
private int _monthScrollBar;
And setting the property value to whatever you want on the constructor.
Note that I'm using MVVM, binding to a property with notification change (so changes are propagating to the View), and initializing it.
Both the ScrollBar and TextBox bind to the same MonthScrollBar property)
If you're doing code behind, you can access it directly from the code behind.

Related

WPF: How do I get X Y position of last character within a TextBox?

I want to have the x, y position of the last character in a TextBox. I found GetCharacterIndexFromPoint method which exactly is a reverse approach. => here
However, I couldn't find the appropriate approach for getting actual position of last character within a TextBox.
Does anyone know how I can get such information?
This question is pretty old now, but I want to give it a try.
My solution for getting the actual position of last character within a TextBox:
MainWindow.xaml:
<StackPanel>
<Label Margin="10" HorizontalAlignment="Center" Content="Enter First Text: " FontSize="20"/>
<TextBox Name="TextBox" Margin="10" Width="200" LostFocus="TextBox_OnLostFocus"/>
<Button Content="GetPositionFromLastCharacter" Width="200" Click="GetLastCharacterFromTextBox"/>
<Label Margin="10" HorizontalAlignment="Center" Content="Enter second Text: " FontSize="20"/>
<TextBox Margin="10" Width="200"/>
</StackPanel>
Method "GetLastCharacterFromTextBox" in MainWindow.xaml.cs
private void GetLastCharacterFromTextBox(object sender, RoutedEventArgs e)
{
int lastCharacterPosition = TextBox.Text.LastIndexOf(TextBox.SelectedText, StringComparison.CurrentCulture);
MessageBox.Show($"Last character from the Text is at position: {lastCharacterPosition}");
}
Output:
WPF Application running
As you can see, I used the "LastIndexOf" Method with the selected text in the TextBox.
Suggestion for showing caret without focusing:
Use the "LostFocus" property on a TextBox and implement the following code:
private void TextBox_OnLostFocus(object sender, RoutedEventArgs e)
{
e.Handled = true;
}
The result is the following:
Showing caret without focus
Even though I have no focus on the first TextBox anymore, the caret is still visible.

WPF - How to restyle ComboBox to remove the textbox/editbox and replace with static text

I want to restyle a WPF ComboBox which is formatted to be a drop-list type, BUT remove the selected TextBox which gets populated with the selected contents and just replace it with some static text and an image which remains constant, simulating a button like look.
So in effect it becomes a button-drop-list, so when I select an item from the drop list, I can populate another control via command bindings with its selected value and the button style remains.
Basically something like this crude picture I've hacked together.
I've seen examples of button with context menus, but I don't like the idea, and a ComboBox fits my needs perfectly in terms of function and easy command and data binding.
I know it can be done, but I lost faith in my ablity after reading overly confusing examples based on other controls. I couldn't find an example detailing my needs to learn from.
Cheers
DIGGIDY
After much playing around, I decided the better option was to go for a button with bound context menu, this worked out to be the better solution in the end.
Thanks for your help Marc.
I had got the same problem and actually, it's simple.
Just put a read-only ComboBox with a SelectionChanged event.
You put in index 0 your static text.
Now, when the user is selecting something, get the selected item and then, set the SelectedIndex to 0. So you got the item the user selected but the displayed text is the same.
See:
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox combo = (ComboBox)sender;
if (combo.SelectedIndex > 0)
{
// Do your stuff here...
// Then
combo.SelectedIndex = 0;
}
}
[EDIT] According to me, I prefer my previous answer. So make sure you, reader, that my previous answer doesn't match your expectations. [/EDIT]
Another answer is to put your object above the ComboBox and then catch the MouseDown event from this object and dropped down the ComboBox. I used a read-only TextBox in my example.
See:
<Grid>
<ComboBox x:Name="Combo" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem Content="TEST" />
<ComboBoxItem Content="TEST1" />
<ComboBoxItem Content="TEST2" />
<ComboBoxItem Content="TEST3" />
</ComboBox>
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" Text="TextBox" VerticalAlignment="Top" Width="120" IsReadOnly="True" PreviewMouseDown="TextBox_PreviewMouseDown"/>
</Grid>
And then the code behind:
private void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true; // Prevents the event.
Combo.IsDropDownOpen = true; // Drops down the ComboBox.
}
It works fine for me.

Binding Single Item of a Collection

I'm just learning the basic concepts of WPF and XAML coming from a C++ background, so some of it is a bit alien to me. I am using Expression Blend to help me get to grips with XAML.
I am making a basic app that displays records in a simple XML data source:
<photos>
<photo>
<image>Assets\Item01.png</image>
<description>Strawberry</description>
</photo>
<photo>
<image>Assets\Item02.png</image>
<description>Orange</description>
</photo>
<photo>
<image>Assets\Item03.png</image>
<description>Pineapple</description>
</photo>
...
</photos>
I have bound this data 'photoDataSource' to a grid and stuck some textboxes and image fields that display the first record. In XAML:
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource photoDataSource}}" Margin="0,0,0,1" Background="#FF1D1D1D">
<Image Height="104" Width="104" Source="{Binding XPath=/photos/photo/image}" Margin="8,62,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<TextBox Height="23" Margin="8,8,6,0" TextWrapping="Wrap" Text="{Binding XPath=/photos/photo/description}" VerticalAlignment="Top"/>
<TextBox Height="23" Margin="8,35,6,0" TextWrapping="Wrap" Text="{Binding XPath=/photos/photo/image}" VerticalAlignment="Top"/>
<Button Content="Next Product" Margin="213,97,297,0" Height="44" VerticalAlignment="Top"/>
</Grid>
This displays two textboxes containing "Strawberry" and "Assets\Item01.png" respectively, along with the image and a Button Containing the text "Next Product". As you can see I have bound the collection "photoDataSource" to the parent Grid. When run it displays the first item in the collection.
How can I trigger the button to display the next item in the collection (and loop) at runtime?
I am not intending to do this with any code-behind as I am not changing any of the data itself, just which item is displayed. But perhaps I am going about this in the wrong way?
Ideally after this example I will want to remove the button completely and change records automatically after a storyboard animation has completed (using the trigger 'StoryboardCompletedTrigger').
Quite right not wanting to use code behind. However I would recommend implementing a ViewModel against your Window to get what you want achieved.
In your view model you should have an ObservableCollection of your Photo object and another property to specify a single Photo being called SelectedPhoto as shown below:
public ObservableCollection<Photo> MyPhotos {
get { return _photos; }
set { _photos = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Photos"));
}
}
public Photo SelectedPhoto {
get { return _photo; }
set { _photo = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("SelectedPhoto"));
}
}
Then use XmlSerialization to load your Xml into the ObservableCollection. Then create your buttons to move next and previous to bind to an ICommand (also in your ViewModel) to cycle up or down the MyPhotos collection setting SelectedPhoto each time.
Then you can bind and Image in your Xaml as follows.
<Image Source="{Binding Source={StaticResource myViewModel}, Path=SelectedPhoto.Image}"/>
I hope this makes some sense for you and has been of some help.

ScrollViewer Control in Wpf

<ScrollViewer VerticalScrollBarVisibility="Auto" >
<TextBlock Text="{Binding Status}"
HorizontalAlignment="Center" />
</ScrollViewer>
The Status always I'm adding to it, that is to say that in the code behind always I do this thing:
Status+= Environment.NewLine + "Hi";
And the ScrollViewer increasing, but the Status that I see is the first one, when I want to see the last one I need to scroll underneath to see it, my question is: how I can made the Scrollviewer scrolling underneath automaticaly?, that meaning I want always see the last status not the first.
Sorry about the broken english.
Name your ScrollViewer so you can access it in the code behind, like this:
<ScrollViewer x:Name="MyScrollViewer" VerticalScrollBarVisibility="Auto" >
<TextBlock Text="{Binding Status}"
HorizontalAlignment="Center" />
</ScrollViewer>
Then you can do this:
Status+= Environment.NewLine + "Hi";
MyScrollViewer.ScrollToEnd();
With the way I do MVVM, I have access to my ViewModel from my View, so when the View first loads, I'd subscribe to the PropertyChanged event on my ViewModel as so:
MyViewModel.PropertyChanged += ViewModelChanged;
and then in the ViewModelChanged callback I'd have this:
private void ViewModelChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Status")
MyScrollViewer.ScrollToEnd();
}
Every time the ViewModel's Status property changes, the ScrollViewer will now scroll to end. Just remember to unsubscribe from MyViewModel.PropertyChanged when you leave that screen to avoid a memory leak.

How to thru char into TextBox?

I have some TextBox on focus ( cursor is blinking on him ).
Now, from other usercontrol ( that contain buttons ) i want to send event that will insert char into the TextBox when pressing any of the buttons that are on the usercontrol.
This need to be without lose the focus from the TextBox ... ( blinking cursor on the TextBox )
How can i do it ?
( i try to raise key down event - but its does not work )
Make your buttons to be not focusable (Focusable = false).
Do you want to use this virtual keyboard with other applications, or is it something that's only going on in your application? Beyond that, if it is only your application, do you only ever want to insert characters into one particular TextBox, or potentially any TextBox?
If it's a virtual keyboard intended to work with any application, then you'll want to use a Win32 API method like SendKeys. WinForms has an extremely easy interface for using SendKeys.
If it only ever needs to add characters to the one TextBox, then it's much more easy to modify the TextBox's Text property rather than trying to raise events on it to get the desired behavior. There's a CaretIndex property that will tell you where to insert the character. Beyond that, it's simple string concatenation.
<StackPanel>
<TextBox Name="MainTextBox" />
<Button Content="A"
Focusable="False"
Click="Button_Click" />
<Button Content="B"
Focusable="False"
Click="Button_Click" />
<Button Content="C"
Focusable="False"
Click="Button_Click" />
<Button Content="D"
Focusable="False"
Click="Button_Click" />
<Button Content="E"
Focusable="False"
Click="Button_Click" />
</StackPanel>
Code:
private void Button_Click(object sender, RoutedEventArgs e)
{
MainTextBox.Text += (sender as Button).Content.ToString();
}
var text = button.Content as string;
textbox.SelectedText = text;
textbox.SelectionLength = 0; // removing selection from inserted text
textbox.SelectionStart += text.Length;
This will insert button content at cursor position (and replace selected text) - the same as user inputted it from keyboard.
PS. if textbox is unknown, it may be found with
var textbox = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this)) as TextBox;
Instead of FocusManager.GetFocusScope(this) you may put window.
If you need it not only for textboxes - WinAPI functions should help. See http://www.pinvoke.net/default.aspx/user32.sendinput

Resources