c# settings + StackOverflowException - c#

I have a usercontrol in my wpf application which is causing a stackoverflowexception to be caught when it is instanced more than once. I tried to debug the cause of the exception and it is raised during InitializeComponent of my Usercontrol. When I enter InitializeComponent it jumps over to the app.xaml.cs codebehind and reads values which are contained in the Settings class.
I am "new" to using C# application settings so I have not experienced this error before. Not sure if this is commonplace or not when working with them. Also, this is the only usercontrol currently in my app that allows modification of the settings variables and it is the only usercontrol which exhibits this behavior.
I think my problem has something to do with the DebugOptions class using a datacontext of "Application.Current" and then I create another instance with that same datacontext but as soon as I access any of its properties I get the application confused about which obj is which. While that makes sense in my head, logically it doesn't work out that way because this usercontrol is instanced upon a button click and it's host panel is cleared before adding to prevent multiple instances from rolling around.
Posted below is the xaml and codebehind of my usercontrol. It has no dependencies except for the CLR properties from the App class that it binds to. I wish I had more info to provide on this but it's a very odd exception that creeps up.
Here is the property in my App class which causes the stackoverflow exception when it is "Get" accessed.
private Byte _debuglevel = Merlin.Properties.Settings.Default.DebugLevel;
public Byte DebugLevel
{
get { return _debuglevel; }
set { _debuglevel = value; }
}
public partial class DebugOptions : UserControl
{
public DebugOptions()
{
InitializeComponent();
}
private void ChangeLogDirectoryButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
MessageBox.Show("Make a decision here...choose to use the old winforms folder browser control or find one on the web because the std openfiledialog can't be overriden to select folders only.", "Fix this..");
}
private void UpdateDebugOptionsButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
//update debug level
Merlin.Properties.Settings.Default.DebugLevel = (Byte)DebugLevelSlider.Value;
//update log boolean
if ((bool)EnableLoggingRadioButton.IsChecked)
{
Merlin.Properties.Settings.Default.LogsEnabled = true;
}
else
{
Merlin.Properties.Settings.Default.LogsEnabled = false;
}
//update log path?
//save "settings"
Merlin.Properties.Settings.Default.Save();
//write a log event noting changes
App myappreference = (App)Application.Current;
Merlin.Helper.logger.pLogToFile(string.Format("Log Settings Updated at {0} by {1}", DateTime.Now.ToString(), myappreference.CurrentUser.UserName));
}
private void OpenLogDirectoryButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
Process process = new Process();
Process.Start("Explorer.exe", Merlin.Properties.Settings.Default.LogsDirectory);
}
}
Usercontrol resources and UserControl tags omitted for brevity
<Border BorderBrush="Black" BorderThickness="1" Margin="0">
<Grid DataContext="{Binding Source={x:Static Application.Current}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Content="Debug Options" HorizontalAlignment="Center" Margin="0" Grid.Row="0" VerticalAlignment="Center" FontSize="29.333" Style="{StaticResource UserControlTitleLabelStyle}" />
<StackPanel Orientation="Horizontal" Grid.Row="1">
<Label Content="Set Debug Level" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Slider x:Name="DebugLevelSlider" HorizontalAlignment="Left" VerticalAlignment="Center" Maximum="10" Value="{Binding DebugLevel}" Minimum="1" Margin="62,0,0,0" TickPlacement="BottomRight" SmallChange="1" Style="{StaticResource SliderStyle1}" Width="119">
<Slider.ToolTip>
<ToolTip Content="{Binding DebugLevel}" ContentStringFormat="{}The current value is {0} out of 10"/>
</Slider.ToolTip>
</Slider>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="2">
<Label Content="Application Level Logging: " />
<RadioButton x:Name="EnableLoggingRadioButton" GroupName="Logs" Content="Enable" Margin="5" IsChecked="{Binding LogsEnabled}">
<RadioButton.ToolTip>
<TextBlock Text="Selecting this option will enable logs at the debug level selected above."/>
</RadioButton.ToolTip>
</RadioButton>
<RadioButton x:Name="DisableLoggingRadioButton" GroupName="Logs" Content="Disable" Margin="5" IsChecked="{Binding Path=IsChecked,ElementName=EnableLoggingRadioButton, Converter={StaticResource oppositebooleanconverter}}" >
<RadioButton.ToolTip>
<TextBlock Text="Selecting this option will disable all logs for the application."/>
</RadioButton.ToolTip>
</RadioButton>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="3">
<Label Content="Log Path" HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBox Margin="10" Width="347.553" TextWrapping="Wrap" Text="{Binding LogsDirectory}" VerticalAlignment="Stretch" />
<StackPanel Height="100">
<Button x:Name="OpenLogDirectoryButton" Content="Open Directory" Width="100" Margin="0,10,0,0" VerticalAlignment="Center" HorizontalAlignment="Right" Style="{StaticResource ButtonStyle}" d:LayoutOverrides="GridBox" Click="OpenLogDirectoryButton_Click" />
<Button x:Name="ChangeLogDirectoryButton" Content="Change Directory" Width="100" Margin="0,10,0,0" VerticalAlignment="Center" HorizontalAlignment="Right" Style="{StaticResource ButtonStyle}" d:LayoutOverrides="GridBox" Click="ChangeLogDirectoryButton_Click" IsEnabled="False" />
</StackPanel>
</StackPanel>
<Button x:Name="UpdateDebugOptionsButton" Content="Update" Grid.Row="4" Width="100" VerticalAlignment="Center" HorizontalAlignment="Right" Style="{StaticResource ButtonStyle}" Click="UpdateDebugOptionsButton_Click" Margin="0,0,8,10" />
</Grid>
</Border>
Stacktrace BEFORE exception thrown
Merlin.exe!Merlin.App.LogsEnabled.set(bool value = false) Line 52 C#
[External Code]
Merlin.exe!Merlin.View.DebugOptions.DebugOptions() Line 25 + 0x8 bytes C#
[External Code]
Merlin.exe!Merlin.View.TestView.TestView() Line 24 + 0x8 bytes C#
Merlin.exe!Merlin.MainWindow.SidebarButtonsClickHandler(object sender = {Merlin.ImageButton}, System.Windows.RoutedEventArgs e = {System.Windows.RoutedEventArgs}) Line 218 + 0x15 bytes C#
[External Code]
What's odd is that during the initializecomponent routine the "LogsEnabled" boolean value is gotten and then immediately it calls to set it. I have no idea what's calling it to set it. But as soon as it sets the value it tries to get it again. I'm sure the runtime is throwing the stackoverflow to prevent an infinite loop. So how can I figure out why it wants to do this?

The stack overflow is probably as a result of a circularly-defined reference: it looks like one way this might happen is that your slider control is bound to DebugLevel. However, when you enter the update method, it defines the value of the DebugLevel to that of the slider control.
So you might get something like:
Slider control's value? Oh - I'll go look up DebugLevel.
DebugLevel's value? Oh, I'll go look up slider control's value.
Slider control's value? Oh - I'll go look up DebugLevel.
I'm not certain, but that could be the problem.
(like the above commenter mentioned, a stack trace would be really helpful here)

Related

Get UserControls dynamically via XamlReader.Load, IsLoaded is false at UI Elements

I try to save and load TabItems via XamlWriter and XamlReader at runtime so that the user can restore the previous session. Each TabItem consists of UserControls and standard WPF controls like grids,buttons and checkboxes.
It all works fine until I try to subscribe to events of let's say a button.
If I raise them manually with RaiseEvent() they work, but if I click on them nothing happens. Even if I set IsEnabled=false the button is displayed as enabled. LogicalTreeHelper.FindLogicalNode gives me the right button, but the Click event also won't trigger. The IsLoaded property is false, so I assume there has to be some underlying problem with the initialization.
Basically this is the code to read from the file
StreamReader sw = new StreamReader(file);
XmlReader xmlReader = XmlReader.Create(sw);
TabItem tabItem = (TabItem)XamlReader.Load(xmlReader);
.. and this to save each TabItem to a seperate xml file
foreach (TabItem tabItem in tabControlMain.Items)
{
StreamWriter sw = new StreamWriter(Path.Combine(path,tabItem.Name + ".xml"), false);
string savedTab = XamlWriter.Save(tabItem);
sw.Write(savedTab);
sw.Close();
}
Here is an example TabItem saved to a file
<TabItem IsSelected="True" Header="Test" Name="tabItem1" HorizontalAlignment="Left" VerticalAlignment="Top" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:womoc="clr-namespace:WeldOsMqttOpcClient;assembly=blabla">
<TabItem.HeaderTemplate>
<DataTemplate DataType="{x:Type TabItem}">
<TextBox Margin="0,0,30,0" Text="{Binding Path=.}" />
</DataTemplate>
</TabItem.HeaderTemplate>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<womoc:UcOverviewTabPage Autoconnect="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="gridParentOv">
<Grid Name="gridMqttOpcControls" Height="599.08" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<womoc:UcConnection Name="ucOpc" MinWidth="400" HorizontalAlignment="Right" VerticalAlignment="Stretch">
<GroupBox Header="OPC [10.5.51.130]" Name="groupBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ScrollViewer>
<Grid Name="gridTextBoxesWithValues" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Name="rowLabel" />
</Grid.RowDefinitions>
<Label Background="#FF008000" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelConnected" Width="190" Height="26" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.ColumnSpan="2">Connected!</Label>
</Grid>
</ScrollViewer>
</GroupBox>
</womoc:UcConnection>
</Grid>
<Grid Name="gridConnection" MinHeight="30" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<Button Name="btnConnect" Width="55" Margin="100,0,0,10" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsEnabled="False">Connect</Button>
<TextBox Name="tbIPAddress" Width="95" Height="18" Margin="0,0,100,10" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsEnabled="False">10.5.51.130</TextBox>
<CheckBox Name="cbMqtt" Width="46" Height="15" Margin="20,0,0,10" HorizontalAlignment="Left" VerticalAlignment="Bottom" IsEnabled="False">Mqtt</CheckBox>
<CheckBox IsChecked="True" Name="cbOpc" Width="42" Margin="0,0,20,10" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsEnabled="False">Opc</CheckBox>
</Grid>
</Grid>
</womoc:UcOverviewTabPage>
</Grid>
</TabItem>
UcOverviewTabPage is one of my UserControls, in which there is for example a button. I try to subscribe to the events manually ->
public UcOverviewTabPage()
{
InitializeComponent();
cbMqtt.Checked += CbMqtt_Checked;
cbMqtt.Unchecked += CbMqtt_Unchecked;
cbOpc.Checked += CbOpc_Checked;
cbOpc.Unchecked += CbOpc_Unchecked;
btnConnect.Click += BtnConnect_Click;
var children = LogicalTreeHelper.FindLogicalNode(this, "btnConnect") as Button;
bool loaded = children.IsLoaded;
// -> FALSE
}
Bear in mind, creating new custom UserControls during runtime works perfectly. The problem only occurs when reading out of the XML file.
I except the UserControls or any other Controls to work like they do when created during runtime. What am I missing?

Is there a workaround to call RegisterAsyncJsObject multiple times while using CefSharp Browser in WPF?

I am using the CefSharp browser in an open source project of mine; a markdown editor to preview the markdown like in the screenshot below:
The relevant XAML is as follows:
<dragablz:TabablzControl TabStripPlacement="Top" Margin="5" ItemsSource="{Binding Documents}" SelectedItem="{Binding CurrentDocument, Mode=TwoWay}" x:Name="TabDocuments" FixedHeaderCount="{Binding CurrentPreferences.IsTabBarLocked, Converter={StaticResource LockTabBarConverter}}">
<dragablz:TabablzControl.HeaderItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10" MaxWidth="10" MinWidth="10"/>
<ColumnDefinition Width="10" MaxWidth="10" MinWidth="10"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Metadata.FileName}"/>
<Thumb Grid.Column="0" Style="{DynamicResource InvisibleThumbStyle}" dragablz:DragablzItem.IsCustomThumb="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding CloseDocumentButtonCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Thumb>
<TextBlock Grid.Column="1" Text="*" Visibility="{Binding IsSaved, Converter={StaticResource VisibilityConverter}}"/>
<Button Grid.Column="2" Width="10" Height="10" MaxWidth="10" MaxHeight="10" MinWidth="10" MinHeight="10" VerticalAlignment="Center" HorizontalAlignment="Right" Command="{Binding CloseDocumentButtonCommand}">
<TextBlock Text="X" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="8" FontWeight="Bold"/>
</Button>
</Grid>
</DataTemplate>
</dragablz:TabablzControl.HeaderItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate x:Name="TabDocumentsDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="Black" BorderThickness="1" Grid.Column="0" Margin="5">
<customControls:CodeTextboxHost Text="{Binding Markdown, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
History="{Binding History, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
RedoStack="{Binding RedoStack, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
FilePath="{Binding Metadata.FilePath}"
WordWrap="{Binding IsWordWrap, UpdateSourceTrigger=PropertyChanged}"
Font="{Binding CurrentFont, UpdateSourceTrigger=PropertyChanged}"
x:Name="CodeTextboxHost"/>
</Border>
<Border BorderBrush="Black" BorderThickness="1" Grid.Column="1" Margin="5">
<wpf:ChromiumWebBrowser Address="{Binding Html, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="ChromiumWebBrowser" Loaded="ChromiumWebBrowser_OnLoaded"/>
</Border>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</dragablz:TabablzControl>
I am now implementing scroll sync. However it is not very straightforward as it is not possible to interact with the browser scroll bars as a normal control. Fortunately, CefSharp browser provides a way to run JavaScript and to link certain classes with certain JavaScript objects. I was able to implement the scroll sync from the textbox control to the browser using these methods.
However I am having issues while implementing the scroll sync from the browser to the textbox control. I will give a brief summary of what I did so far first.
On every document's HTML file I have the following script:
window.onscroll = function (e) {
var maxValue = document.getElementsByTagName('body')[0].scrollHeight - document.getElementsByTagName('body')[0].clientHeight;
var minValue = 0;
var value = e.target.body.scrollTop;
cefChromimumBrowser.browserScrollChange(value, maxValue, minValue);
}
This script gets the max value, min value and the actual scroll value and sends it to the C# side. To make the "transfer", I have an event listener which performs the following when the browser is first loaded:
private void ChromiumWebBrowser_OnLoaded(object sender, RoutedEventArgs e)
{
var browser = (ChromiumWebBrowser)sender;
browser.RegisterAsyncJsObject("cefChromimumBrowser", CefChromiumBrowserManager.GetInstance());
}
This, registers cefChromimumBrowser object that I have in the JavaScript as an instance of CefChromiumBrowserManager. In CefChromiumBrowserManager I have a method such as this:
public void BrowserScrollChange(int value, int maxValue, int minValue)
{
var scrollResult = new ScrollResult
{
MaxValue = maxValue,
MinValue = minValue,
Value = value
};
SharedEventHandler.GetInstance().RaiseOnBrowserScrollChanged(scrollResult);
}
When the OnBrowserScrollChanged event is raised, it changes the scroll position on the textbox control.
This works perfectly when there is only 1 tab. As soon as I open another tab I got the "Browser is already initialized. RegisterJsObject must be called before the underlying CEF browser is created." error.
I checked the CefSharp documentation and this is indeed the case, the browser is initialized once per application which is discussed here. And it is only possible to use RegisterAsyncJsObject right after the browser is first initialized, which is documented here.
So I tried a second approach, thinking maybe if the registered JavaScript is the same, it would pick it up without registering it again:
private void ChromiumWebBrowser_OnLoaded(object sender, RoutedEventArgs e)
{
if (!_isBrowserInitialized)
{
var browser = (ChromiumWebBrowser)sender;
browser.RegisterAsyncJsObject("cefChromimumBrowser", CefChromiumBrowserManager.GetInstance());
_isBrowserInitialized = true;
}
}
I got rid of the error but now the scroll only worked in the first tab and it didn't work in the rest of the tabs.
My question is; can I somehow transfer the "register" to the second tab (or the active tab if there are multiple tabs) so that the scroll sync from browser to textbox works?

Checking specific radiobutton when navigate to page

In a windows 8.1 project i have a ListView that displays several items that look something like this:
I basically display agenda points, that can have 2 sub levels
if subpoint at first level has no subpoints itself it is a radiobutton, otherwise the subpoints it contains are radiobuttons.
the radiobutton points have this template.
<DataTemplate x:Key="WithSubTemplate2">
<Grid Width="280" Height="50" Margin="85,0,0,0" HorizontalAlignment="Right">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5" />
</Grid.RowDefinitions>
<RadioButton GroupName="meetingFiles" Tag="{Binding}" Checked="RadioButton_Checked" Content="{Binding Name}" Style="{StaticResource RadioButtonStyle1}"></RadioButton>
<Ellipse Width="20" Height="20" Fill="#b3d0dd" HorizontalAlignment="Right" Margin="0,0,10,0"></Ellipse>
<TextBlock Text="{Binding AttachmentNumber}" HorizontalAlignment="Right" FontFamily="Segoe UI Regular" FontSize="16" Foreground="{StaticResource BrandBrush}" Margin="0, 14,15,0"></TextBlock>
<Grid x:Name="whiteLine" Grid.Row="1" Width="270" Height="1" Background="#80b0c6" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
When i check one of the radio buttons, i have a control that displays a pdf, and then when i want to edit that pdf it navigates to another page.
What i want is, when i go back to the previous page to have the RadioButton i checked earlier to be checked when the page opens.
Any way i can achieve this?
You can simply use:
this.NavigationCacheMode = NavigationCacheMode.Required;
That'll save current page status :).

wpf user control - how to set text from outer uc

i have a problem , i have 2 uc that displayed in main windows.
i want when i press on button in the first uc the text in the other uc will change
this the axml i use and the code
first uc
<Grid.RowDefinitions>
<RowDefinition ></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Width="40" Height="40" Name="playbtn" HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" Click="playbtn_Click" >
<Button.Content>
<Image Source="/img/player_play.png" ></Image>
</Button.Content>
</Button>
<Button Width="40" Height="40" Name="pausebtn" Grid.Column="1" Grid.Row="0" >
<Button.Content>
<Image Source="/img/player_pause.png" ></Image>
</Button.Content>
</Button>
<Button Width="40" Height="40" Name="stopbtn" Grid.Column="2" Grid.Row="0" >
<Button.Content>
<Image Source="/img/player_stop.png" ></Image>
</Button.Content>
</Button>
</Grid>
</StackPanel>
</Grid>
</StackPanel>
secound uc <TextBlock Name="Progresstimertext" Text="00:00:00" FontSize="20"></TextBlock>
so i want to press on start button and the timer will be change? how to
10x
This should be managed in the View Model of your Main Window, as this seems the only location that has knowledge of both controls and it sounds as though each of your user control's shouldn't necessarily have knowledge of each other.
Ideally, you should have a reference to each of your user controls in the code-behind (or view model class is you have a dedicated one).
If in code behind, you would simply expose these by giving them names.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="your controls reference here">
<Grid>
<Grid.ColumnDefinitions>
</ColumnDefinition>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<controls:UserControl1 x:Name="Control1"/>
<controls:UserControl2 x:Name="Control2" Grid.Column="1"/>
</Grid>
</Window>
Now you can reference them in your code behind by name Control1 and Control2. These user control classes should be exposing the properties that you want to control, in your case ProgressTimerText, such that, in the code-behind, you can set it easily such as
Control2.ProgressTimerText = "00:00:00";
Where to do this? Well you probably want to create a Stopped event on your Control1, that you can attach to your code behind - in your case, something like Stopped. In your UserControl1 class you should declare something like
public event EventHandler Stopped;
And then in the local event handler for the Click of the stop button, invoke that event.
private void Stop_Click(object sender, RoutedEventArgs e)
{
if (Stopped != null)
Stopped(this, e);
}
Attach that in your MainWindow:
<controls:UserControl1 x:Name="Control1" Stopped=Control1_Stopped/>
Now in your code-behind you should have something like:
private void Control1_Stopped(object sender, RoutedEventArgs e)
{
Control2.ProgressTimerText = "00:00:00";
}

Silverlight, itemcontrol LostFocus and GetFocus not firing

Okay, so the situation as like this:
I've got an ItemsControl, which contains several children.
the children are actually a UserControl, this is it's Xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--DAY HEADER-->
<Border x:Name="dayHeader" Height="20" BorderBrush="#B0B6BE" BorderThickness="1" Grid.Row="0" Background="{StaticResource WeekHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center"
TextWrapping="NoWrap" Margin="1.5,0,0,0" Text="18"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center"
TextWrapping="NoWrap" Margin="2,0,0,0" Text="Thuesday" />
</Grid>
</Border>
<!--DAY HOURS-->
<ItemsControl x:Name="dayHours" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Name="dayHourBorder" Height="30" BorderBrush="#B0B6BE" Width="193" Tag="{Binding Index}" BorderThickness="1,0,1,1" Background="AliceBlue"
MouseLeftButtonDown="dayHourBorder_MouseLeftButtonDown" MouseLeftButtonUp="dayHourBorder_MouseLeftButtonUp"
MouseMove="dayHourBorder_MouseMove" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
IN SHORT
it's a grid that in the first row has a border
and in the second row has an ItemsControl.
Alright now... what i wanna do is, whenever i click between the child ItemControls (day hours) i want them to execute some function on the LostFocus() event and on GotFocus() event.
problem is... they don't fire! and it tried registering to them from every possible angle!
HALP.
UPDATE
I tried executing Focus() on MouseLeftButtonDown, but what happened is, it went straight to OnLostFocus, which is not what i want...
i don't understand it
Here is an overview on focus in Silverlight. The article mentions four conditions that need to be satisfied in order for the control to get focus. You should check those four conditions for your control and it should be fine I suppose.
You should also consider on which element you'd like to receive those events as GotFocus and LostFocus are bubbling events.
I've managed to fix this issue by doing this:
doing: this.Focus();
and then: e.Handled = true;
the problem was that the ItemControl usually can't hold focus, and so the click event bubbles up.
but when i tell him it's Handled, it stops it's bubbling and won't lose the focus.

Categories

Resources