TabItem contents disabled when selecting different tabs - silverlight

We have an issue whereby when closing a shared control (within a child window) when a different tab, other than the first tab is selected, the contents of the tab are disabled are subsequently disabled when reloading the control. However, if you select a different tab and navigate back to the original tab, the contents are then enabled.
Does anybody have an insight to what is causing the original disabling effect & a fix for this as I am struggling with this one?
XAML
<customTab:CustomTabControl x:Name="ctcNoteTabControl" Margin="10">
<customTab:CustomTabItem Header="Details">
<Border Background="White" CornerRadius="10">
...
</Border>
</customTab:CustomTabItem>
<customTab:CustomTabItem Header="Attachments / Email Alerts">
<Border Background="White" CornerRadius="10">
...
</Border>
</customTab:CustomTabItem>
<customTab:CustomTabItem Header="Assets" x:Name="ctiAssets">
<Border Background="{StaticResource CurveBlockBackground}" CornerRadius="10" Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2">
...
</Border>
</customTab:CustomTabItem>
</customTab:CustomTabControl>
C# - Custom class inheriting from TabControl
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ReACTSL.Control
{
public class CustomTabControl : TabControl
{
protected override void OnKeyDown(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Home:
case Key.End:
e.Handled = true;
break;
default:
break;
}
base.OnKeyDown(e);
}
}
}
C# - Custom class inheriting from TabItem
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ReACTSL.Control
{
public class CustomTabItem : TabItem
{
protected override void OnKeyDown(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Home:
case Key.End:
case Key.Left:
case Key.Right:
case Key.Up:
case Key.Down:
e.Handled = true;
break;
default:
break;
}
base.OnKeyDown(e);
}
}
}

I have found the answer and thankfully it is not a TabControl related problem.
After further investigation, the problem only occurred upon clicking the Save button and not the Cancel or child windows close button. The only difference between these, apart from a service call to save the contents, is the use of the BusyIndicator control from the same System.Windows.Controls.dll for Silverlight 5 (SDK).
This was being displayed whilst the service call was being executed
busyIndicator.IsBusy = true;
However it is was never being stopped from displaying once the service call had returned and the response had been processed. As the control is shared, this meant that the tab which was selected when the Save button was clicked, remained disabled, for some reason I am not sure about.
I simply set the IsBusy property to false before closing the shared control and everything was enabled upon re-opening the shared control.
busyIndicator.IsBusy = false;

Related

WPF fade-in window animation using opacy is not very smooth at the first time

I want to display a window using a standard fade-in effect. Everything works well but the first time I load and show the window the fade in animation is not very smooth. If I close and show it again the animation works better.
Any way to improve the fade-in at the first time?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Windows.Media.Animation;
namespace Kiosk
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
TimeSpan fadeTime = TimeSpan.FromMilliseconds(250);
var fadeInAnimation = new DoubleAnimation(1d, fadeTime);
BeginAnimation(Window.OpacityProperty, fadeInAnimation);
}
}
}

Easiest way to implement a WPF Listbox with an Observable Collection

I see tons of questions on this topic and the answers are, in my limited C# and WPF experience, overly complex. I cannot believe that Microsoft has made it this difficult (to me ) to implement a collection bound to a Listbox that changes during runtime.
Here's the deal: I have a Listbox that contains items (list of emails, actually). What occurs is that I need the Listbox to refresh when a new email arrives or gets removed from the source Folder. Sounds easy enough, but manipulating the Observable Collection in anyway is causing the dreaded "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread."
So nevermind for a moment about circumventing this problem by writing dispatcher stuff. Is there some "normal" way to manipulate a collection that's NOT from another thread? -- this is what I'm confused on. Where else would I modify the collection? I'd happily place my code there if this is what's expected.
My current implementation -- which may very well be poor -- is to place the Folder.Items event handlers within the collection class itself that will then add/remove emails from the collection (i.e. itself). This ain't working and I don't really understand how else one would accomplish this.
Okay, I whipped up this code example. This is NOT my application but it pretty much represents how I'm (incorrectly) handling things...and this will throw the 'cannot update source collection thread error'. The example is broken into 3 sections, first is the XAML markup, then Main class and method and the ObservableCollection class.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="WpfApplication1.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" >
<Border BorderBrush="#FF404020" BorderThickness="5" Margin="0" Background="#FFFFFFC0" CornerRadius="25">
<ListBox x:Name="lbList" Margin="50" FontSize="21.333" DisplayMemberPath="Subject"/>
</Border>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Text;
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.Shapes;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MailList ml = new MailList();
public MainWindow()
{
this.InitializeComponent();
Microsoft.Office.Interop.Outlook.Application olApp = Marshal.GetActiveObject("Outlook.Application") as Microsoft.Office.Interop.Outlook.Application;
Folder f = (Folder)olApp.Session.PickFolder(); // User picks MAPI Folder
f.Items.ItemAdd += new ItemsEvents_ItemAddEventHandler(this.UpdateListBox); //Folder.Item add event, calls UpdateListBox
foreach (object o in f.Items)
{
if (o is MailItem)
{
ml.Add((MailItem)o); //Add Mailitems to ml collection
}
}
Binding b = new Binding(); //create binding for ListBox
b.Mode = BindingMode.OneWay;
lbList.DataContext = ml;
lbList.SetBinding(ListBox.ItemsSourceProperty, b);
}
public void UpdateListBox(object o) //Add new MailItem to ml collection
{
if (o is MailItem)
{
ml.Add((MailItem)o);
}
}
}
}
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Outlook;
namespace WpfApplication1
{
public class MailList : ObservableCollection<MailItem>
{
public MailList()
: base()
{
}
}
}
What is supposed to be the problem with dispatching collection changes to the UI-thread? As far as i know that is the usual way to go.

Init grid row height doesn't work

this is my simple try-it application that create a grid with 2 rows. The 1st row's height is bound to a properties. The value I assigned to it only works at run-time. I tried to make it also work when design-time but I failed to do that (I used this thread to write my app).
Please help me to see what I miss. Thank you!
[Edit]
The reason why I do this is that I want to set dynamically the height of the top grid row, ie. Grid.Row="0", to be the title bar height. Somewhere in my app, the view loaded and overlap the title bar.
You're trying to do a very strange trick, which is not supposed to work. Try to make the following changes.
MainWindow.xaml.cs -- try to always keep you code-behind clear.
namespace WpfTryIt
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
MainWindow.xaml
<Window x:Class="WpfTryIt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
xmlns:s ="clr-namespace:WpfTryIt"
>
<Window.DataContext>
<s:FakeDataContext></s:FakeDataContext>
</Window.DataContext>
<Button Content="{Binding Path=BindingHeight}"/>
</Window>
And a new separate data context class, which behave different depending on the mode:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows;
namespace WpfTryIt
{
public class FakeDataContext
{
public int BindingHeight
{
get
{
// Check for design mode.
if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue))
{
//in Design mode
return 100;
}
else
{
return 200;
}
}
}
}
}

How to set RichTextBox Font for the next text to be written?

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.

WPF Storyboard does not pause

I have a very simple Storyboard with an Int32Animation that targets a custom DP on my class.
I have an OnChanged callback for my DP, that does a Console.WriteLine("Current Value: " + MyDP).
When I run the storyboard, I can see the Console output just fine, and when I pause the storyboard, the Console output stops, BUT, when I resume the storyboard, the DP is NOT the next value at it should be. It continues increasing even though the storyboard has stopped.
Has anyone had anything like this happen to them?
here is a code snippet of what Im doing
Int32Animation element = new Int32Animation();
element.From = 0;
element.To = targetTo;
element.Duration = dur;
Storyboard.SetTargetProperty(element, new PropertyPath(CurrentFrameProperty));
_filmstripStoryboard = new Storyboard {SpeedRatio = this.FrameRate};
_filmstripStoryboard.Children.Add(element);
public void Start()
{
_filmstripStoryboard.Begin(this, true);
}
public void Pause()
{
_filmstripStoryboard.Pause(this);
}
public void Unpause()
{
_filmstripStoryboard.Resume(this);
}
There's a thread in the MSDN forums where Microsoft confirms that this behavior (the current value continuing even when the storyboard is paused for a while) is a bug in the then-current (as of 2006) release of WPF. The forum thread includes a suggested workaround, specifically, save off the current position when you pause, and manually seek back to that same position when you resume.
The thread mentions that they were thinking about fixing the bug in a future version, but I do not know whether .NET 3.5 or 4.0 actually fixed this bug or not.
EDIT: It appears that the bug is fixed in .NET 4.0 -- I was able to pause and then resume an animation without it jumping forward across the intervening time. (I didn't test in 3.5.)
Now there is no bug in 4.0 . Below code works fine.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfAnimation.Win1805787"
xmlns:Local="clr-namespace:WpfAnimation"
x:Name="MyWindow"
Title="Win1805787"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox HorizontalAlignment="Right" VerticalAlignment="Top" Width="75" Text="{Binding CurrentFrame, ElementName=MyWindow}" Height="20" Margin="5,0,5,5"/>
<Button x:Name="Play1" Content="Play" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Play_Click" Margin="5,0,5,5"/>
<Button x:Name="Pause1" Content="Pause" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75" Click="Pause_Click" Margin="5,0,5,5"/>
<Button x:Name="Resume1" Content="Resume" HorizontalAlignment="Right" VerticalAlignment="Top" Width="75" Click="Resume_Click" Margin="5,0,5,5"/>
</StackPanel>
</Grid>
</Window>
/////////////////////////
using System;
using System.Collections.Generic;
using System.Text;
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.Shapes;
using System.Windows.Media.Animation;
namespace WpfAnimation
{
/// <summary>
/// Interaction logic for Win1805787.xaml
/// </summary>
public partial class Win1805787 : Window
{
public Win1805787()
{
this.InitializeComponent();
_createStoryBoard();
// Insert code required on object creation below this point.
}
public int CurrentFrame
{
get { return (int)GetValue(CurrentFrameProperty); }
set { SetValue(CurrentFrameProperty, value); }
}
// Using a DependencyProperty as the backing store for CurrentFrame. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentFrameProperty =
DependencyProperty.Register("CurrentFrame", typeof(int), typeof(Win1805787),
new PropertyMetadata(0, new PropertyChangedCallback(OnValueChanged)));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
Storyboard _filmstripStoryboard;
void _createStoryBoard()
{
Int32Animation element = new Int32Animation();
element.From = 0;
element.To = 100;
element.Duration = Duration.Plus(new Duration(new TimeSpan(1000000000)));
Storyboard.SetTargetProperty(element, new PropertyPath(CurrentFrameProperty));
_filmstripStoryboard = new Storyboard { SpeedRatio = 0.5 };
_filmstripStoryboard.Children.Add(element);
}
private void Play_Click(object sender, System.Windows.RoutedEventArgs e)
{
_filmstripStoryboard.Begin(this, true);
}
private void Pause_Click(object sender, System.Windows.RoutedEventArgs e)
{
_filmstripStoryboard.Pause(this);
}
private void Resume_Click(object sender, System.Windows.RoutedEventArgs e)
{
_filmstripStoryboard.Resume(this);
}
}
}

Resources