I have a problem that is driving me crazy, I am working on a project in WPF and I am creating a view.
I was designing a window which contains a "More Options" section, I had even been able to make this section show or hide. This section contained a tabControl which contained a TextBox as bellow:
<TabControl Margin="10,156,12,39" Name="moreTabControl" Grid.Column="1">
<TabItem >
<Grid>
<TextBox Margin="6,6,8,28" Name="myTextBox" />
</Grid>
</TabItem>
</TabControl>
So, in the code behind what I do to show or hide the "More Section" is as following:
public partial class FilterView : System.Windows.Window
{
.....
// Window's height when "more" option are showed
private const int ShowMoreHeight = 386;
/// Window's height when "more" option are hidden
private const int ShowLessHeight = 186;
private bool showMore = false;
private void moreButton_Click(object sender, RoutedEventArgs e)
{
showMore = !showMore;
ResizeWindow();
}
private void ResizeWindow()
{
if (showMore)
{
moreTabControl.Visibility = System.Windows.Visibility.Visible;
moreButton.Content = "<< Less";
MinHeight = ShowMoreHeight;
Height = ShowMoreHeight;
}
else
{
moreTabControl.Visibility = System.Windows.Visibility.Collapsed;
moreButton.Content = "More >>";
MinHeight = ShowLessHeight;
Height = ShowLessHeight;
}
}
......
.....
}
Everything went well until I needed to change the TextBox for a RichTextBox :(, when I run the program and press the "MoreButton" the "more" section is showed as expected but the container window grows a lot to the right!
And I only changed this: <TextBox Margin="6,6,8,28" Name="myTextBox" /> for this: <RichTextBox Margin="6,6,8,28" Name="myRichTextBox" />
Does anyone know what is happening??
Thank you in advance.
I have solved my problem:
Turns out that in my XAML code, my Window had a property called SizeToContent set to "WidthAndHeight", so I changed it to "Manual" and established a value for Width and Height manually.
Hope this helps some else who is experiencing somethig similar.
Related
I need to set the font family for the next text to be written in a RichTextBox.
I tried setting that with...
<RichTextBox x:Name="RichTextEditor" MaxWidth="1000" SpellCheck.IsEnabled="True"
FontFamily="{Binding ElementName=TextFontComboBox, Path=SelectedItem}"
FontSize="{Binding ElementName=TextSizeComboBox, Path=SelectedValue}"
Width="Auto" Height="Auto" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto" />
...but it changed the whole text. I suppose that with the Selection property I can restrict the change to be applied just to the selected area. But how for the next -not yet typed- text?
In order to set the FontFamily based on the cursor position you need to define a custom control with a dependency property that helps insert a new Run section by overriding the OnTextInput method.
I included most of the code, you'll need to modify the namespaces to fit your development environment.
The code uses a ViewModel to manage the available fonts and manage if the font changed.
This code is only a prototype and does not deal with focusing issues between the two controls.
To use this code:
1- Type some text in the RichTectBox.
2- Change the font in the ComboBox.
3- Tab back to the RichTextBox.
4- Type some more text.
Here is the custom RichTextBox control:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace RichTextboxFont.Views
{
public class RichTextBoxCustom : RichTextBox
{
public static readonly DependencyProperty CurrentFontFamilyProperty =
DependencyProperty.Register("CurrentFontFamily",
typeof(FontFamily), typeof
(RichTextBoxCustom),
new FrameworkPropertyMetadata(new FontFamily("Tahoma"),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnCurrentFontChanged)));
public FontFamily CurrentFontFamily
{
get
{
return (FontFamily)GetValue(CurrentFontFamilyProperty);
}
set
{
SetValue(CurrentFontFamilyProperty, value);
}
}
private static void OnCurrentFontChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{}
protected override void OnTextInput(TextCompositionEventArgs e)
{
ViewModels.MainViewModel mwvm = this.DataContext as ViewModels.MainViewModel;
if ((mwvm != null) && (mwvm.FontChanged))
{
TextPointer textPointer = this.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
Run run = new Run(e.Text, textPointer);
run.FontFamily = this.CurrentFontFamily;
this.CaretPosition = run.ElementEnd;
mwvm.FontChanged = false;
}
else
{
base.OnTextInput(e);
}
}
}
}
Here is the XAML:
<Window x:Class="RichTextboxFont.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RichTextboxFont.Views"
xmlns:ViewModels="clr-namespace:RichTextboxFont.ViewModels"
Title="Main Window"
Height="400" Width="800">
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ComboBox ItemsSource="{Binding Path=Fonts}"
SelectedItem="{Binding Path=SelectedFont, Mode=TwoWay}"/>
<local:RichTextBoxCustom Grid.Row="1"
CurrentFontFamily="{Binding Path=SelectedFont, Mode=TwoWay}"
FontSize="30"/>
</Grid>
</DockPanel>
</Window>
Here is the ViewModel:
If you do not use view models, let me know and I'll add the base class code too; otherwise, google/stackoverflow can help you too.
using System.Collections.ObjectModel;
using System.Windows.Media;
namespace RichTextboxFont.ViewModels
{
public class MainViewModel : ViewModelBase
{
#region Constructor
public MainViewModel()
{
FontFamily f1 = new FontFamily("Georgia");
_fonts.Add(f1);
FontFamily f2 = new FontFamily("Tahoma");
_fonts.Add(f2);
}
private ObservableCollection<FontFamily> _fonts = new ObservableCollection<FontFamily>();
public ObservableCollection<FontFamily> Fonts
{
get
{
return _fonts;
}
set
{
_fonts = value;
OnPropertyChanged("Fonts");
}
}
private FontFamily _selectedFont = new FontFamily("Tahoma");
public FontFamily SelectedFont
{
get
{
return _selectedFont;
}
set
{
_selectedFont = value;
FontChanged = true;
OnPropertyChanged("SelectedFont");
}
}
private bool _fontChanged = false;
public bool FontChanged
{
get
{
return _fontChanged;
}
set
{
_fontChanged = value;
OnPropertyChanged("FontChanged");
}
}
#endregion
}
}
Here is the Window code-behind where I initialise the ViewModel:
using System.Windows;
namespace RichTextboxFont.Views
{
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
this.DataContext = new ViewModels.MainViewModel();
}
}
}
There's a much easier way to do this: Implement a toolbar for your RichTextBox.
Unlike WinForms, the RichTextBox in WPF doesn't come with a toolbar by default, but it's really easy to create one yourself. The RichTextBox automatically handles many EditingCommands, so it's just a matter of creating a toolbar and some buttons. Microsoft has provided sample code for this at the bottom of the RichTextBox Overview on MSDN.
Unfortunately, those editing commands don't include setting the FontFace property of the selection, though you can create a ComboBox on the toolbar that can trigger the change with an event handler in the codebehind file.
That's the approach taken in this CodePlex article by Gregor Pross: WPF RichTextEditor
The project is commented in German, but the source itself is very clearly written. The codebehind used for his font selector ComboBox looks like this:
private void Fonttype_DropDownClosed(object sender, EventArgs e)
{
string fontName = (string)Fonttype.SelectedItem;
if (fontName != null)
{
RichTextControl.Selection.ApplyPropertyValue(System.Windows.Controls.RichTextBox.FontFamilyProperty, fontName);
RichTextControl.Focus();
}
}
The main reason that people struggle with the FontFace selection is that after the font selection has been made, you must return focus to the RichTextBox. If the user must manually press tab or click into the RichTextBox, a new text selection gets created and you lose the formatting options you've chosen.
One of the answers to this StackOverflow question discusses that problem.
WPF Richtextbox FontFace/FontSize
This isn't exactly a trivial answer.
To do inline text formatting in a Rich TextBox like you want you will have to modify the Document property of the RichTextBox. Very simply, something like this will work
<RichTextBox >
<RichTextBox.Document>
<FlowDocument>
<Paragraph>
<Run>Something</Run>
<Run FontWeight="Bold">Something Else</Run>
</Paragraph>
</FlowDocument>
</RichTextBox.Document>
</RichTextBox>
I think you could create a custom Control that creates a new block element and sets the font properties you need based on the user input.
For example, If the user types something then presses bold. You would want to wrap the previous text in a run and create a new run element setting the FontWeight to bold then the subsequent text will be wrapped in the bolded run.
Again, not a trivial solution but I can't think of any other way to accomplish what you are after.
How to achieve an automatic full screen that not hides the taskbar, with no resize and no window style?
I tried to use the following code, but it doesn't work right, as shown in the image below.
XAML:
<Window x:Class="WPF_Test_Environment.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowState="Maximized" ResizeMode="NoResize" WindowStyle="None">
<DockPanel>
<Button DockPanel.Dock="Top" Height="50">Top</Button>
<Button DockPanel.Dock="Bottom" Height="50">Bottom</Button>
<Button DockPanel.Dock="Left" Width="50">Left</Button>
<Button DockPanel.Dock="Right" Width="50">Right</Button>
<Button Width="50" Height="50">Center</Button>
</DockPanel>
</Window>
Code-Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
MinHeight = SystemParameters.MaximizedPrimaryScreenHeight;
MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth;
MinWidth = SystemParameters.MaximizedPrimaryScreenWidth;
}
}
Here is the result:
As you can see, the "Bottom" button is partially underneath the taskbar, and I want it to be entirely above it. So, ideally, it would look as shown in the following image, but without the border on the top:
It can be done with calls to unmanaged code. Check this article to see how to do it. Basically, just remove your width and height settings from code-behind, implement the WindowSizing class from the article and call it from SourceInitialized event of the window.
Edit
The other solution would be to add reference to Windows Forms and use:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Set the width and height values to the values of working area
this.Width = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width;
this.Height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
// Move the window to top left corner of the screen
this.Left = 0;
this.Top = 0;
}
Just make sure to remove WindowState="Maximized" from your window.
Not sure if any of these is elegant though.
In my main page I try to show a list of stuff, and on this stuff a userControl as an overlay. In fact I never see it. (In the design view, my userControl is oaky)
XAML MainPage
<Grid>
<Grid x:name="MyPage">
<!-- All this part is visible -->
//Button
//Button
//nice Pic
//Button
</Grid>
<cat:CatPagecontrol x:Name="CatTool" Visibility="Visible" HorizontalAlignment="Center" VerticalAlignment="Center">
<cat:CatPagecontrol.Transitions>
<TransitionCollection>
<PopupThemeTransition/>
</TransitionCollection>
</cat:CatPagecontrol.Transitions>
</cat:CatPagecontrol>
<!-- EDIT I remove the Grid "CatGrid" And the ZIndex -->
</Grid>
I try to switch the ZIndex, no results.
C# File
public MainView()
{
this.CatTool = new CatPagecontrol();
//this.CatTool.Visibility = Visibility.Collapsed;
}
private void showCatSelector()
{
this.CatTool.Visibility = Visibility.Visible;
}
After that I need that one of my buttons show the overlay when clicked.
If you know how to show it, I'm yours. Thanks.
edit : solution find.
Voila !
I've find my problem :
public CatPagecontrol()
{
this.InitializeComponent();
}
I just Initialized in the correct section.
I tried a few things about adding my own created user control element to listbox or stackpanel, but instead of gaining any success, it causes a NullReferenceException and I have no idea why ...
my user control is looking like that:
public partial class ShiftInformationItem : UserControl
{
public ShiftInformationItem()
{
InitializeComponent();
}
}
and the xaml:
<Grid>
<LabelContent="Benutzername:" />
<Label Content="01.03.2014 14:19" />
<TextBox Text="Eintrag ..." />
<Expander Header="Comments (0)">
<Grid Background="#FFE5E5E5"/>
</Expander>
</Grid>
Inside the main window I can add it in a listbox or a stackpanel without any Trouble:
<ListBox>
<controls:ShiftInformationItem />
</ListBox>
or:
<StackPanel Name="ShiftInformationPanel">
<controls:ShiftInformationItem />
</StackPanel>
But when I try to add it with C#:
ShiftInformationList.Items.Add(new ShiftInformationItem());
ShiftInformationPanel.Children.Add(new ShiftInformationItem());
it causes the NullReferenceException and says the object I want to add is null.
Does anybody can explain me why?
Im very thankful for all well meaned and helpful answers in advance!
UPDATE:
public partial class HoBusReceptionMain : Window
{
public HoBusReceptionMain()
{
InitializeComponent();
}
private void RibbonWin_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
RibbonTab r = (RibbonTab)e.AddedItems[0];
switch (r.Header.ToString())
{
case "Shift Information":
InitializeShiftInformationTab();
break;
default:
MessageBox.Show(e.AddedItems[0].ToString());
break;
}
}
private void InitializeShiftInformationTab()
{
//here I want to add the new ShiftInformationItem
}
}
UPDATE 2:
Thanks all comments, it Shows up, that my list || Panel is null ... But both is included in the main window (above HoBusReceptionMain)
I use Ribbons in my application, and when a ribbon tab is selected or loaded the RibbonWin_SelectionChanged Event is fired ... The list or Panel defined below the ribbon definitions
I suspect you are adding that before InitializeComponent() gets called.
Move the code of adding below InitializeComponent() and it will work like it did from XAML. Issue is controls were not initialized before InitializeComponent() gets called and hence resulting in NullReferenceException.
public MainWindow()
{
InitializeComponent();
ShiftInformationList.Items.Add(new ShiftInformationItem());
ShiftInformationPanel.Children.Add(new ShiftInformationItem());
// ShiftInformationPanel is null here
}
Here is a very simple code example:
<DockPanel>
<ToolBar DockPanel.Dock="Top" IsTabStop="False">
<ToggleButton MinWidth="40" Command="EditingCommands.ToggleBold" CommandTarget="{Binding ElementName=XAMLRichBox}" TextBlock.FontWeight="Bold" IsTabStop="False">B</ToggleButton>
</ToolBar>
<RichTextBox x:Name="XAMLRichBox" SpellCheck.IsEnabled="True" MinHeight="100"/>
</DockPanel>
when I run it, after typing something into the RichTextBox, I can use the ToggleButton to get the BOLD effect, and everything is fine.
But if I click ToggleButton before typing in anything into RichTextBox (no matter RichTextBox get focus or not), although ToggleButton became Checked, my RichTextBox still using the normal style (not BOLD) until I click ToggleButton again.
Is this a bug? how can I get around? Thanks!
Mainwindow.xaml
<DockPanel>
<ToolBar
DockPanel.Dock="Top"
IsTabStop="False">
<ToggleButton
x:Name="boldButton"
Command="EditingCommands.ToggleBold"
CommandTarget="{Binding ElementName=XAMLRichBox}"
TextBlock.FontWeight="Bold"
ToolTip="Bold">
B
</ToggleButton>
</ToolBar>
<RichTextBox
x:Name="XAMLRichBox"
SpellCheck.IsEnabled="True"
SelectionChanged="SynchronizeWith"
MinHeight="100" />
</DockPanel>
Mainwindow.xaml.cs
private void SynchronizeWith(object sender, RoutedEventArgs e)
{
object currentValue = XAMLRichBox.Selection.GetPropertyValue(TextElement.FontWeightProperty);
boldButton.IsChecked = (currentValue == DependencyProperty.UnsetValue) ? false : currentValue != null && currentValue.Equals(FontWeights.Bold);
}
I found a semi-solution and I thought I would share since this problem is not answered anywhere on the web and I think many people are having issues with it.
I set a Variable NewInput in the constructor. When the first input in the richTextBox will be fired, I'll just apply every formating I need to it and pass it to the control.
private bool NewInput;
private void richTxt_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (NewInput)
{
richTxt.BeginChange();
TextPointer startPosition = richTxt.Selection.Start;
Run r = new Run(e.Text, startPosition);
if (IsSelectionBold)
{
r.FontWeight = FontWeights.Bold;
}
if (IsSelectionItalic)
{
r.FontStyle = FontStyles.Italic;
}
if (IsSelectionUnderlined)
{
r.TextDecorations = TextDecorations.Underline;
}
r.FontSize = double.Parse(SelectedFontHeight);
r.FontFamily = new FontFamily(SelectedFont);
richTxt.EndChange();
NewInput = false;
e.Handled = true;
richTxt.CaretPosition = richTxt.CaretPosition.GetPositionAtOffset(1);
}
}
I then replace the carret at the right place. Like this, the formating is kept even if there is nothing in the RichTextBox.
I'm sure it'll help somebody one day.
#Sinity was close, but that solution does not work when the caret is placed within the text block, only if it is at the very end.
There are two positions at the end of a Run: Run.ContentEnd and Run.ElementEnd. It appears that the ContentEnd is "just outside" the run (so any new text entered does not take on the run's style), but ElementEnd is "just inside" the end of the run, and the typed text is added into the run.
Here is a modified solution (that applies a pending Bold style as an example) that seems to work in all cases:
private bool IsBoldStylePending { get; set; }
private void RichTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (!IsBoldStylePending)
return;
rtb.BeginChange();
Run run = new Run(e.Text, rtb.CaretPosition); // Add the next character with style
run.FontWeight = FontWeights.Bold;
rtb.EndChange();
rtb.CaretPosition = run.ElementEnd; // Keep caret just within the run
IsBoldStylePending = false;
e.Handled = true;
}