WPF window that have a content control with Prism region manager and region name.
Prism region have a user control that injected to it.
Window open and fully loaded, after reconnect with RDP, the window Prism region lost the injected view.
I figure out that on RDP reconnecting the widow is updating layout and re render, loading event is firing and UpdateLayout as well.
Any idea ?
I already observe the following solution but it doesn’t helped on this one.
WPF: Prevent unload & load after RDP (dis)connect
<ContentControl x:Name="DetailRegion" Grid.Row="1"
Visibility="{Binding IsAgentVisible,`enter code here`
Converter={StaticResource BoolVisibilityConverter},
ConverterParameter=Collapsed}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Focusable="False"
Padding="5"
regions:RegionManager.RegionManager="{Binding CvaRegionManager,UpdateSourceTrigger=PropertyChanged}"
regions:RegionManager.RegionName="StandAloneCVAViewRegion" />
When RDP reconnecting the control hosting the content control is recreated. I can solve the problem by creating the Prism region by c# code, thus I can handle the case of recreation of the control and check if Region already store a view.
private void CvaControl_Loaded(object sender, RoutedEventArgs e)
{
SetRegionManager(this.DetailRegion, "StandAloneCVAViewRegion");
}
void SetRegionManager(DependencyObject regionTarget, string regionName)
{
var cvaRegionManager = ((CvaApplicationViewModel) DataContext).CvaRegionManager;
if (cvaRegionManager.Regions.ContainsRegionWithName("StandAloneCVAViewRegion"))
{
this.DetailRegion.Content = cvaRegionManager.Regions["StandAloneCVAViewRegion"].ActiveViews.First();
return;
}
RegionManager.SetRegionName(regionTarget, regionName);
RegionManager.SetRegionManager(regionTarget,cvaRegionManager);
}
Related
I just encountered a serious problem with Context Menu which I cannot resolve for hours.
To reproduce the problem I created a brand new Panorama app with the app templates for Windows Phone 8 in Visual Studio 2012. I installed Windows Phone toolkit via nugget and add context menu in the data template of the first long list selector which is bound to Items
<StackPanel Margin="0,-6,0,12">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="{StaticResource PhoneFontSizeExtraLarge}"/>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="{Binding LineOne}" Click="MenuItem_Click_1" Tag="{Binding}">
</toolkit:MenuItem>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</StackPanel>
I set the header to the LineOne property for easier debugging. I attached the following event:
private void MenuItem_Click_1(object sender, RoutedEventArgs e)
{
var itemViewModel = (ItemViewModel)((MenuItem)sender).Tag;
App.ViewModel.Items.Remove(itemViewModel);
App.ViewModel.Items.Add(new ItemViewModel { LineOne = "Test", LineTwo = "Test", LineThree = "Test" });
}
I run the app and use the context menu to remove the first item. The first item disappears and a new item named Test appears at the bottom of the list as expected. If I hold this new item the menu item is bound to "runtime one" (the item that was deleted).
This was the simplest code I could get to reproduce the error but in my real app I have pretty much the same problem with more meaningful code for adding and deleting in different methods and even different pages. I had a command bound but since the databinding is wrong the command is run in the wrong view model with the wrong parameter.
Any idea why this is happening?
For those like me not wanting to recompile toolkit here is an easy workaround based on pantaloons answer. Simpy add Opened event handler:
<toolkit:ContextMenu Opened="ContextMenu_Opened">
...
</toolkit:ContextMenu>
Event Handler code:
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
var menu = (ContextMenu)sender;
var owner = (FrameworkElement)menu.Owner;
if (owner.DataContext != menu.DataContext)
menu.DataContext = owner.DataContext;
}
The LongListSelector is a virtualized control, which means it instantiates the DataTemplate you specify a fixed number of times (20, I think), and then reuses those Item containers as you scroll down the list, simply moving them around and rebinding their DataContext's. That way, you can have extremely large lists without needing the whole lot to be in the Visual Tree.
The ContextMenu code, at http://phone.codeplex.com/SourceControl/changeset/view/80797#1335947 has the following lines in the OpenPopup() function;
if (ReadLocalValue(DataContextProperty) == DependencyProperty.UnsetValue)
{
DependencyObject dataContextSource = Owner ?? _rootVisual;
SetBinding(DataContextProperty, new Binding("DataContext") { Source = dataContextSource });
}
You'll see that there is a bug here because when the virtualized container rebinds the DataContext, it will not get updated on the _rootVisual, since it's assumed the existing DataContext is the right one. The fix would be to change that check to be:
if (ReadLocalValue(DataContextProperty) == DependencyProperty.UnsetValue ||
(DataContext != dataContextSource.DataContext))
{
DependencyObject dataContextSource = Owner ?? _rootVisual;
SetBinding(DataContextProperty, new Binding("DataContext") { Source = dataContextSource });
}
I have a C# WPF .NET 4 application that has an icon in the system tray. I am currently using the well-discussed WPF NotifyIcon, but the problem I am having is not dependent on this control. The problem is that .NET 4 simply does not allow (for the most part) a WPF ContextMenu object to appear over the top of the Windows 7 taskbar. This example illustrates the problem perfectly.
XAML:
<Window x:Class="TrayIconTesting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="100" Width="400">
<Window.Resources>
<ContextMenu x:Key="TrayContextMenu" Placement="MousePoint">
<MenuItem Header="First Menu Item" />
<MenuItem Header="Second Menu Item" />
</ContextMenu>
<Popup x:Key="TrayPopup" Placement="MousePoint">
<Border Width="100" Height="100" Background="White" BorderBrush="Orange" BorderThickness="4">
<Button Content="Close" Click="ButtonClick"></Button>
</Border>
</Popup>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<Label Target="{Binding ElementName=UseWinFormsMenu}" VerticalAlignment="Center">
<AccessText>Use WinForms context menu for tray menu:</AccessText>
</Label>
<CheckBox Name="UseWinFormsMenu" IsChecked="False" Click="UseWinFormsMenuClicked" VerticalAlignment="Center" />
</StackPanel>
</Window>
Code:
using System.Drawing;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Forms;
using ContextMenu = System.Windows.Controls.ContextMenu;
namespace TrayIconTesting
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ContextMenuStrip winFormsContextMenu;
public MainWindow()
{
InitializeComponent();
this.TrayIcon = new NotifyIcon
{
Icon = new Icon("Bulb.ico"),
Visible = true
};
this.TrayIcon.MouseClick += (sender, args) =>
{
switch (args.Button)
{
case MouseButtons.Left:
this.TrayPopup.IsOpen = true;
break;
case MouseButtons.Right:
if (!this.UseWinFormsMenu.IsChecked.GetValueOrDefault())
{
this.TrayContextMenu.IsOpen = true;
}
break;
}
};
}
private void ButtonClick(object sender, RoutedEventArgs e)
{
this.TrayPopup.IsOpen = false;
}
private void UseWinFormsMenuClicked(object sender, RoutedEventArgs e)
{
this.TrayIcon.ContextMenuStrip = this.UseWinFormsMenu.IsChecked.GetValueOrDefault() ? this.WinFormsContextMenu : null;
}
private ContextMenu TrayContextMenu
{
get
{
return (ContextMenu)this.FindResource("TrayContextMenu");
}
}
private Popup TrayPopup
{
get
{
return (Popup)this.FindResource("TrayPopup");
}
}
private NotifyIcon TrayIcon
{
get;
set;
}
private ContextMenuStrip WinFormsContextMenu
{
get
{
if (this.winFormsContextMenu == null)
{
this.winFormsContextMenu = new ContextMenuStrip();
this.winFormsContextMenu.Items.AddRange(new[] { new ToolStripMenuItem("Item 1"), new ToolStripMenuItem("Item 2") });
}
return this.winFormsContextMenu;
}
}
}
}
To see the problem make sure that the tray icon is always visible and not part of that Win7 tray icon popup thing. When you right click on the tray icon the context menu opens ABOVE the taskbar. Now right click one of the standard Windows tray icons next to it and see the difference.
Now, left click on the icon and notice that it DOES allow a custom popup to open right where the mouse cursor is.
Checking the "Use WinForms..." checkbox will switch the app to use the old ContextMenuStrip context menu in the Windows.Forms assembly. This obviously opens the menu in the correct place, but its appearance doesn't match the default Windows 7 menus. Specifically, the row highlighting is different.
I have played with the Horizontal and VerticalOffset properties, and with the "right" values you can make the context menu popup all the way at the bottom right of the screen, but this is just as bad. It still never opens where your cursor is.
The real kicker is that if you build this same sample targeting .NET 3.5 it works just as expected. Unfortunately, my real application uses many .NET 4 features, so reverting back is not an option.
Anyone have any idea how to make the context menu actually open where the cursor is?
After a little more searching I stumbled across this question & answer. I never thought to try the ContextMenu property on the NotifyIcon! While not ideal it will work well enough until WPF address the fact that the system tray is a useful part of applications. It will really be a shame to lose all the binding and command routing features provided by the WPF ContextMenu though.
It feels wrong to accept my own answer though, so I'm going to leave this open for a few more days.
Well, I'm glad didn't mark this as answered because I found a slightly better option for me. I found this article that details how to add icons to the System.Windows.Forms.MenuItem object. Now with just a little code I have a menu that perfectly matches system context menus!
I have seen a few posts addressing how to remove an UserControl that has been added during runtime, but my problem is a little different. I have a UserControl that consists of an image with a small "x" button on the top right corner that is used to remove itself (the UserControl) from its parent canvas. Also to note is that the UserControl is added during runtime when the user doubleclicks on a ListboxItem. I have a Click event handler for the top right corner button but this code is not running at all. I know this because I have a breakpoint in this code which is not reached when I click the button.
So,
Why isn't the click event of the remove button being handled?
Maybe there is a better way to implement this. Please advise.
Here's the code used for adding it:
private void MyListBox_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (e.OriginalSource.ToString() == "System.Windows.Controls.Border" || e.OriginalSource.ToString() == "System.Windows.Controls.Image" || e.OriginalSource.ToString() == "System.Windows.Controls.TextBlock")
{
Expression.Blend.SampleData.MyCollection.Dataset lbi = ((sender as ListBox).SelectedItem as Expression.Blend.SampleData.MyCollection.Dataset);
var new_usercontrol = new MyUserControl();
new_usercontrol.MyImageSourceProperty = lbi.Image;
MyCanvas.Children.Add(new_usercontrol);
Canvas.SetLeft(new_usercontrol, 100);
Canvas.SetTop(new_usercontrol, 100);
Canvas.SetZIndex(new_usercontrol, 100);
}
}
The following is the cs code for the UserControl:
public partial class ModuleElement : UserControl
{
public ImageSource MyProperty
{
get { return (ImageSource)this.image.Source; }
set { this.image.Source = value; }
}
public ModuleElement()
{
this.InitializeComponent();
}
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
((Canvas)this.Parent).Children.Remove(this);
}
}
The XAML:
<Grid x:Name="LayoutRoot">
<Image x:Name="image" />
<Button x:Name="RemoveButton" Content="X" HorizontalAlignment="Right" Height="17.834" Margin="0" VerticalAlignment="Top" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Click="RemoveButton_Click">
</Button>
</Grid>
Thanks in advance,
Bryan
So I tried your code here exactly except for some name changes and could not reproduce your issue. In my personal experience your issue here has to be that for some reason the event for the click isn't subscribed to properly. For this I would go into designer for the user control, wipe out the current event for the button and double click in the designer event textbox such that VS or Blend generates all the code necessary for a proper subscription.
I have created a sample based on your code here. Feel free to pull it down and take a look to see if you can find any inconsistencies.
As far as a better way to implement this, check out the good old MVVM pattern and the MVVM Light Toolkit. With this you can have a central ViewModel class that will handle all of your button commands and binding without code behind.
If we have
<ScrollViewer Name="scroll_viewer" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Canvas Name="canvas" Height="200" Width="200">
<Rectangle Fill="AliceBlue" Width="100" Height="100"/>
</Canvas>
</ScrollViewer>
with handlers for:
scroll_viewer.PreviewMouseLeftButtonDown
scroll_viewer.MouseLeftButtonDown
canvas.PreviewMouseLeftButtonDown
Then if we click in the Rectangle we get scroll_viewer_PreviewMouseLeftButtonDown called first then canvas_PreviewMouseLeftButtonDown but scroll_viewer_MouseLeftButtonDown is not called.
I want to handle the click event first in the canvas - if an object is clicked I want to handled the event (for object drag). If no canvas object is clicked I want to handle event in scroll_viewer (to manage scrollview panning with the mouse).
How to manage this given that the call order is the oposite of what i want and that the non perview version scroll_viewer.MouseLeftButtonDown is not called?
UPDATE:
From this post: Silverlight forums
((FrameworkElement)scroll_viewer.GetValue(ScrollViewer.ContentProperty)).MouseLeftButtonDown += scroll_viewer_MouseLeftButtonDown;
DOES work ie does get called after the preview events - can some explain why this less than obvious syntax is required?
The problem is that the ScrollViewer already handles the MouseLeftButtonDown event internally, like so:
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
if (base.Focus())
e.Handled = true;
base.OnMouseLeftButtonDown(e);
}
You can "fix" this using a custom class, like so:
public class MyScrollViewer : ScrollViewer {
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
base.OnMouseLeftButtonDown(e);
e.Handled = false;
}
}
SIDE NOTE: You should use x:Name in XAML, not Name. Otherwise you may run into compilation errors using the above class.
Alternatively, you could attach your handler for all MouseLeftButtonDown events, including handled ones. So instead of:
this.scroll_viewer.MouseLeftButtonDown += new MouseButtonEventHandler(scroll_viewer_MouseLeftButtonDown);
You'd use:
this.scroll_viewer.AddHandler(ScrollViewer.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.scroll_viewer_MouseLeftButtonDown), true);
The Preview events follow a routing strategy similar to the Tunneling strategy, meaning that the event starts at the top of the element tree, and travels down it. So it would hit your ScrollViewer first, then your Canvas.
The non-Preview events follow a routing strategy similar to the Bubbling strategy, meaning that events start on the object they occurred on, and travel up the element tree. In this case, the Canvas would get hit first, then the ScrollViewer.
You can read more about the Routing strategies here
As a side note, for Canvas objects to be visible for HitTest events, they need to have a non-transparent background. So if you have a Canvas with no background color specified, it will default to Transparent and not be visible for HitTests.
I am facing a very unusual problem, i have a UserControl which shows ChildWindow to perform some operation on this ChildWindow, i close it when done with my operations and the (say) open it again, it works fine, but as soon as i close this ChildWindow, the UserControl becomes disabled.
This happens for all the ChildWindows on my application i.e, if i open (say) ChildWindow01 and then close it and then open ChildWindow02 and close it, the base UserControl becomes disabled.
Its a MVVM application but i am opening these ChildWindows from UserControl.xaml.cs, button click events.
P.S. I am using Galasoft MVVM framework for my application.
Please suggest.
Edit
UserControl XAML
<StackPanel Style="{StaticResource QuizEditorStackPanelStyle}">
<HyperlinkButton x:Name="lnkSetting" Content="Settings"
Command="{Binding QuizSettingCommand}" CommandParameter="{Binding SettingId}"/>
</StackPanel>
calls ViewModel -> RelayCommand, which opens a child window (which is a private property in VM) as
private ChildWindow QuizSettingWindow {
get {
return new QuizSetting(this.QuizSettingId);
}
}
Child Window opens by
private void OpenQuizSettingScreen(long quizSettingId) {
this.QuizS ettingWindow.Show();
}
Child window close on button event of self
On closing the child window are you unsubscribing the closing event or not? Not sure if that could be the reason for your problem. Try unsubscribing from the closing event of child window.
I have found this thread on the silverlight forums, I also had this problem. The thread explains your problem and gives it a temporary fix. This fixed worked for me.
If you call
Application.Current.RootVisual.SetValue(Control.IsEnabledProperty, True);
After you closed the window the parent will always be enabled. This fix worked for me and I hope it will work for you too.
But if in your case only one user control blocks (and not the entire app) then you might want to call something like
this.SetValue(Control.IsEnabledProperty, True);
Or if you subscribe to the close event from within the childwindow (if you extend it) then you might consider calling:
this.Parent.SetValue(Control.IsEnabledProperty, True);
I haven't tested any of those. But in my case the first worked. I hope this all helps you with your problem.