Reputation: 527
I am having some issues with my code and I was hoping you could help.
I am attempting to learn WPF/XAML, and as part of that learning process I decided to make a basic text editor to test my own skills. I want to make a combo box for font size that will resize all text based on the value in the combo box (basically like any other text editor, but I can not figure out how to make this work. Here is my XAML so far:
<Window x:Class="DataBinding.UsingCommandsSample"
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:DataBinding"
mc:Ignorable="d"
Title="MainWindow" WindowState="Maximized" >
<DockPanel>
<Menu DockPanel.Dock="Top" Margin="0 0 0 10">
<MenuItem Header="_File" Name="file">
<MenuItem Header="Open File" Click="btnOpenFile_Click"/>
<MenuItem Header="Save File" Click="btnSaveFile_Click">
<MenuItem Header="Save As" Click="btnSaveAs_Click" />
</MenuItem>
<MenuItem Header="Save As" Click="btnSaveAs_Click" />
<MenuItem Command="Print" />
</MenuItem>
<MenuItem Header="_Edit" Name="edit">
<MenuItem Command="Copy" />
<MenuItem Command="Cut" />
<MenuItem Command="Paste" />
<MenuItem Command="SelectAll" />
<MenuItem Command="Undo" />
<MenuItem Command="AlignLeft" />
<MenuItem Command="EditingCommands.AlignCenter" />
<MenuItem Command="AlignRight" />
<MenuItem Command="AlignJustify" />
</MenuItem>
</Menu>
<ToolBarTray DockPanel.Dock="Top" Height="auto">
<ToolBar>
<Button Command="Cut" Content="Cut" />
<Button Command="Copy" Content="Copy" />
<Button Command="Paste" Content="Paste" />
<ComboBox x:Name="fontBox" SelectedValue="selected" SelectionChanged="fontBox_SelectionChanged">
<ComboBoxItem Content="12" IsSelected="True"/>
<ComboBoxItem Content="16" />
<ComboBoxItem Content="18" />
<ComboBoxItem Content="20" />
</ComboBox>
</ToolBar>
</ToolBarTray>
<TextBox Name="txtEditor" AcceptsReturn="True" />
</DockPanel>
</Window>
And here is my Code-Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Microsoft.Win32;
using System.IO;
namespace DataBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class UsingCommandsSample : Window
{
public UsingCommandsSample()
{
InitializeComponent();
}
public string path;
private void btnOpenFile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
txtEditor.Text = File.ReadAllText(openFileDialog.FileName);
path = openFileDialog.FileName;
}
private void btnSaveFile_Click(object sender, RoutedEventArgs e)
{
if (path != null)
File.WriteAllText(path, txtEditor.Text);
else
MessageBox.Show("You have not specified a location to which the file should be saved. Click 'OK' then File >> Save As.", "Cannot find path", MessageBoxButton.OK, MessageBoxImage.Warning);
}
private void btnSaveAs_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "Text file (*.txt)|*txt | Banana (*.banana)|*.cs";
if (saveFileDialog.ShowDialog() == true)
File.WriteAllText(saveFileDialog.FileName, txtEditor.Text);
}
private void fontBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int temp;
if (Int32.TryParse(fontBox.Text, out temp))
{
txtEditor.FontSize = temp;
}
}
}
}
For some reason, the Font Size does indeed update, but only after i select a different ComboBoxItem. For example, If I start with "12" selected, then select "14", nothing will happen. If I then select "16", the font size will change to 14. I imagine that the operations are happening in an order I don't want them to, but I am stumped as to why or how to fix that.
If anyone could give me a hand on this one, I would really appreciate it. I can't seem to find any other resources, so StackOverflow is my last hope.
Upvotes: 1
Views: 2365
Reputation: 2620
Here is a simple scenario :
<Window x:Class="TestComboFont.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:TestComboFont"
xmlns:vm="clr-namespace:TestComboFont.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<ComboBox x:Name="fontsCombo"
ItemsSource="{Binding FontSizes}"
SelectedItem="{Binding SelectedFont, UpdateSourceTrigger=PropertyChanged}"
Margin="10,5"/>
<TextBox Grid.Row="1"
Background="WhiteSmoke"
Margin="10"
AcceptsReturn="True"
FontSize="{Binding SelectedFont, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
And voila the view model :
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<int> FontSizes { get; set; }
private int _selectedFont;
public int SelectedFont
{
get { return _selectedFont; }
set
{
_selectedFont = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedFont)));
}
}
public MainViewModel()
{
FontSizes = new ObservableCollection<int>() { 10, 15, 20 };
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
That's it.
Your ComboBox
is bound to FontSizes
ObservableCollection
which resides in the MainViewModel
.
In order to get this behavior you need a DataContext
for your Window
:
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
Every time you select an item, SelectedFont
will be changed and with it, the FontSize
property of the TextBox
too, because in turn you have a binding set here :
FontSize="{Binding SelectedFont, UpdateSourceTrigger=PropertyChanged}"
I think, it might be a good option to follow, using MVVM even there is no Model in this example.
Upvotes: 1
Reputation: 1496
The problem is that when the event fires to say the combo has changed, it hasn't actually finished changing yet so you're getting the existing value (12) rather than the new value (14). Next time you'd get the 14 instead of the newly selected 16, which is why you're always one step behind.
I would have bound the combo box instead of doing it the way you've done it, but here's a quick'n'dirty solution.
private void fontBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox cbox = (ComboBox)sender;
ComboBoxItem t = (ComboBoxItem) cbox.SelectedItem;
string NewSetting = (string) t.Content;
int temp;
if (Int32.TryParse(NewSetting, out temp))
{
if(txtEditor != null)
txtEditor.FontSize = temp;
}
}
You need the check for txtEditor being null because when the page is loading for the first time the combo box will trigger this event while it's initialising, which is before the txtEditor has been initialised.
Upvotes: 1